1/* $NetBSD: klock.c,v 1.11 2023/06/23 21:09:44 riastradh Exp $ */ 2 3/* 4 * Copyright (c) 2007-2010 Antti Kantee. All Rights Reserved. 5 * 6 * Development of this software was supported by the 7 * Finnish Cultural Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31#include <sys/cdefs.h> 32__KERNEL_RCSID(0, "$NetBSD: klock.c,v 1.11 2023/06/23 21:09:44 riastradh Exp $"); 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/evcnt.h> 37 38#include <rump-sys/kern.h> 39 40#include <rump/rumpuser.h> 41 42/* 43 * giant lock 44 */ 45 46struct rumpuser_mtx *rump_giantlock; 47static int giantcnt; 48static struct lwp *giantowner; 49 50static struct evcnt ev_biglock_fast; 51static struct evcnt ev_biglock_slow; 52static struct evcnt ev_biglock_recurse; 53 54void 55rump_biglock_init(void) 56{ 57 58 evcnt_attach_dynamic(&ev_biglock_fast, EVCNT_TYPE_MISC, NULL, 59 "rump biglock", "fast"); 60 evcnt_attach_dynamic(&ev_biglock_slow, EVCNT_TYPE_MISC, NULL, 61 "rump biglock", "slow"); 62 evcnt_attach_dynamic(&ev_biglock_recurse, EVCNT_TYPE_MISC, NULL, 63 "rump biglock", "recurse"); 64} 65 66void 67rump_kernel_bigwrap(int *nlocks) 68{ 69 70 KASSERTMSG(giantcnt > 0, "giantcnt=%d", giantcnt); 71 KASSERTMSG(curlwp == giantowner, "curlwp=%p giantowner=%p", 72 curlwp, giantowner); 73 giantowner = NULL; 74 *nlocks = giantcnt; 75 giantcnt = 0; 76} 77 78void 79rump_kernel_bigunwrap(int nlocks) 80{ 81 82 KASSERT(giantowner == NULL); 83 giantowner = curlwp; 84 giantcnt = nlocks; 85} 86 87void 88_kernel_lock(int nlocks) 89{ 90 struct lwp *l = curlwp; 91 92 while (nlocks) { 93 if (giantowner == l) { 94 giantcnt += nlocks; 95 nlocks = 0; 96 ev_biglock_recurse.ev_count++; 97 } else { 98 if (rumpuser_mutex_tryenter(rump_giantlock) != 0) { 99 rump_unschedule_cpu1(l, NULL); 100 rumpuser_mutex_enter_nowrap(rump_giantlock); 101 rump_schedule_cpu(l); 102 ev_biglock_slow.ev_count++; 103 } else { 104 ev_biglock_fast.ev_count++; 105 } 106 giantowner = l; 107 giantcnt = 1; 108 nlocks--; 109 } 110 } 111} 112 113void 114_kernel_unlock(int nlocks, int *countp) 115{ 116 117 if (giantowner != curlwp) { 118 KASSERT(nlocks == 0); 119 if (countp) 120 *countp = 0; 121 return; 122 } 123 124 if (countp) 125 *countp = giantcnt; 126 if (nlocks == 0) 127 nlocks = giantcnt; 128 if (nlocks == -1) { 129 KASSERT(giantcnt == 1); 130 nlocks = 1; 131 } 132 KASSERT(nlocks <= giantcnt); 133 while (nlocks--) { 134 giantcnt--; 135 } 136 137 if (giantcnt == 0) { 138 giantowner = NULL; 139 rumpuser_mutex_exit(rump_giantlock); 140 } 141} 142 143bool 144_kernel_locked_p(void) 145{ 146 147 return giantowner == curlwp; 148} 149 150void 151rump_user_unschedule(int nlocks, int *countp, void *interlock) 152{ 153 154 _kernel_unlock(nlocks, countp); 155 /* 156 * XXX: technically we should unschedule_cpu1() here, but that 157 * requires rump_intr_enter/exit to be implemented. 158 */ 159 rump_unschedule_cpu_interlock(curlwp, interlock); 160} 161 162void 163rump_user_schedule(int nlocks, void *interlock) 164{ 165 166 rump_schedule_cpu_interlock(curlwp, interlock); 167 168 if (nlocks) 169 _kernel_lock(nlocks); 170} 171