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 46 struct rumpuser_mtx *rump_giantlock; 47 static int giantcnt; 48 static struct lwp *giantowner; 49 50 static struct evcnt ev_biglock_fast; 51 static struct evcnt ev_biglock_slow; 52 static struct evcnt ev_biglock_recurse; 53 54 void 55 rump_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 66 void 67 rump_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 78 void 79 rump_kernel_bigunwrap(int nlocks) 80 { 81 82 KASSERT(giantowner == NULL); 83 giantowner = curlwp; 84 giantcnt = nlocks; 85 } 86 87 void 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 113 void 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 143 bool 144 _kernel_locked_p(void) 145 { 146 147 return giantowner == curlwp; 148 } 149 150 void 151 rump_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 162 void 163 rump_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