1.\" $NetBSD: KERNEL_LOCK.9,v 1.2 2022/02/15 22:58:25 wiz Exp $ 2.\" 3.\" Copyright (c) 2022 The NetBSD Foundation, Inc. 4.\" All rights reserved. 5.\" 6.\" Redistribution and use in source and binary forms, with or without 7.\" modification, are permitted provided that the following conditions 8.\" are met: 9.\" 1. Redistributions of source code must retain the above copyright 10.\" notice, this list of conditions and the following disclaimer. 11.\" 2. Redistributions in binary form must reproduce the above copyright 12.\" notice, this list of conditions and the following disclaimer in the 13.\" documentation and/or other materials provided with the distribution. 14.\" 15.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25.\" POSSIBILITY OF SUCH DAMAGE. 26.\" 27.Dd February 13, 2022 28.Dt KERNEL_LOCK 9 29.Os 30.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 31.Sh NAME 32.Nm KERNEL_LOCK 33.Nd compatibility with legacy uniprocessor code 34.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 35.Sh SYNOPSIS 36.In sys/systm.h 37.\" 38.Ft void 39.Fn KERNEL_LOCK "int nlocks" "struct lwp *l" 40.Ft void 41.Fn KERNEL_UNLOCK_ONE "struct lwp *l" 42.Ft void 43.Fn KERNEL_UNLOCK_ALL "struct lwp *l" "int *nlocksp" 44.Ft void 45.Fn KERNEL_UNLOCK_LAST "struct lwp *l" 46.Ft bool 47.Fn KERNEL_LOCKED_P 48.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 49.Sh DESCRIPTION 50The 51.Nm 52facility serves to gradually transition software from the kernel's 53legacy uniprocessor execution model, where the kernel runs on only a 54single CPU and never in parallel on multiple CPUs, to a multiprocessor 55system. 56.Pp 57.Sy New code should not use Nm . 58.Nm 59is meant only for gradual transition of 60.Nx 61to natively MP-safe code, which uses 62.Xr mutex 9 63or other 64.Xr locking 9 65facilities to synchronize between threads and interrupt handlers. 66Use of 67.Nm 68hurts system performance and responsiveness. 69This man page exists only to document the legacy API in order to make 70it easier to transition away from. 71.Pp 72The kernel lock, sometimes also known as 73.Sq giant lock 74or 75.Sq big lock , 76is a recursive exclusive spin-lock that can be held by a CPU at any 77interrupt priority level and is dropped while sleeping. 78This means: 79.Bl -tag -width "held by a CPU" 80.It recursive 81If a CPU already holds the kernel lock, it can be acquired again and 82again, as long as it is released an equal number of times. 83.It exclusive 84Only one CPU at a time can hold the kernel lock. 85.It spin-lock 86When one CPU holds the kernel lock and another CPU wants to hold it, 87the second CPU 88.Sq spins , 89i.e., repeatedly executes instructions to see if the kernel lock is 90available yet, until the first CPU releases it. 91During this time, no other threads can run on the spinning CPU. 92.Pp 93This means holding the kernel lock for long periods of time, such as 94nontrivial computation, must be avoided. 95Under 96.Dv LOCKDEBUG 97kernels, holding the kernel lock for too long can lead to 98.Sq spinout 99crashes. 100.It held by a CPU 101The kernel lock is held by a CPU, not by a process, kthread, LWP, or 102interrupt handler. 103It may be shared by a kthread LWP and several softint LWPs at the same 104time, for example, if the softints interrupted the thread on a CPU. 105.It any interrupt priority level 106The kernel lock 107.Em does not 108block interrupts; subsystems running with the kernel lock use 109.Xr spl 9 110to synchronize with interrupt handlers. 111.Pp 112Interrupt handlers that are not marked MP-safe are always run with the 113kernel lock. 114If the interrupt arrives on a CPU where the kernel lock is already 115held, it is simply taken again recursively on interrupt entry and 116released to its original recursion depth on interrupt exit. 117.It dropped while sleeping 118Any time the kernel sleeps to let other threads run, for any reason 119including 120.Xr tsleep 9 121or 122.Xr condvar 9 123or even adaptive 124.Xr mutex 9 125locks, it releases the kernel lock before going to sleep and then 126reacquires it afterward. 127.Pp 128This means, for instance, that although data structures accessed only 129under the kernel lock won't be changed before the sleep, they may be 130changed by another thread during the sleep. 131For example, the following program may crash on an assertion failure 132because the sleep in 133.Xr mutex_enter 9 134can allow another CPU to run and change the global variable 135.Dv x : 136.Bd -literal 137 KERNEL_LOCK(1, NULL); 138 x = 42; 139 mutex_enter(...); 140 ... 141 mutex_exit(...); 142 KASSERT(x == 42); 143 KERNEL_UNLOCK_ONE(NULL); 144.Ed 145.Pp 146This means simply introducing calls to 147.Xr mutex_enter 9 148and 149.Xr mutex_exit 9 150can break kernel-locked assumptions. 151Subsystems need to be consistently converted from 152.Nm 153and 154.Xr spl 9 155to 156.Xr mutex 9 , 157.Xr condvar 9 , 158etc.; mixing 159.Xr mutex 9 160and 161.Nm 162usually doesn't work. 163.El 164.Pp 165Holding the kernel lock 166.Em does not 167prevent other code from running on other CPUs at the same time. 168It only prevents other 169.Em kernel-locked 170code from running on other CPUs at the same time. 171.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 172.Sh FUNCTIONS 173.Bl -tag -width abcd 174.It Fn KERNEL_LOCK nlocks l 175Acquire 176.Fa nlocks 177recursive levels of kernel lock. 178.Pp 179If the kernel lock is already held by another CPU, spins until it can 180be acquired by this one. 181If the kernel lock is already held by this CPU, records the kernel 182lock recursion depth and returns immediately. 183.Pp 184Most of the time 185.Fa nlocks 186is 1, but code that deliberately releases all of the kernel locks held 187by the current CPU in order to sleep and later reacquire the same 188number of kernel locks will pass a value of 189.Fa nlocks 190obtained from 191.Fn KERNEL_UNLOCK_ALL . 192.It Fn KERNEL_UNLOCK_ONE l 193Release one level of the kernel lock. 194Equivalent to 195.Fo KERNEL_UNLOCK 196.Li 1 , 197.Fa l , 198.Dv NULL 199.Fc . 200.It Fn KERNEL_UNLOCK_ALL l nlocksp 201Store the kernel lock recursion depth at 202.Fa nlocksp 203and release all recursive levels of the kernel lock. 204.Pp 205This is often used inside logic implementing sleep, around a call to 206.Xr mi_switch 9 , 207so that the same number of recursive kernel locks can be reacquired 208afterward once the thread is reawoken: 209.Bd -literal 210 int nlocks; 211 212 KERNEL_UNLOCK_ALL(l, &nlocks); 213 ... mi_switch(l) ... 214 KERNEL_LOCK(nlocks, l); 215.Ed 216.It Fn KERNEL_UNLOCK_LAST l 217Release the kernel lock, which must be held at exactly one level. 218.Pp 219This is normally used at the end of a non-MP-safe thread, which was 220known to have started with exactly one level of the kernel lock, and is 221now about to exit. 222.It Fn KERNEL_LOCKED_P 223True if the kernel lock is held. 224.Pp 225To be used only in diagnostic assertions with 226.Xr KASSERT 9 . 227.El 228.Pp 229The legacy argument 230.Fa l 231must be 232.Dv NULL 233or 234.Dv curlwp , 235which mean the same thing. 236.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 237.Sh NOTES 238Some 239.Nx 240kernel abstractions execute caller-specified functions with the kernel 241lock held by default, for compatibility with legacy code, but can be 242explicitly instructed 243.Em not 244to hold the kernel lock by passing an MP-safe flag: 245.Bl -bullet 246.It 247.Xr callout 9 , 248.Dv CALLOUT_MPSAFE 249.It 250.Xr kfilter_register 9 251and 252.Xr knote 9 , 253.Dv FILTEROPS_MPSAFE 254.It 255.Xr kthread 9 , 256.Dv KTHREAD_MPSAFE 257.It 258.Xr pci_intr 9 , 259.Dv PCI_INTR_MPSAFE 260.It 261.Xr scsipi 9 , 262.Dv SCSIPI_ADAPT_MPSAFE 263.It 264.Xr softint 9 , 265.Dv SOFTINT_MPSAFE 266.It 267.Xr usbdi 9 268pipes, 269.Dv USBD_MPSAFE 270.It 271.Xr usbdi 9 272tasks, 273.Dv USB_TASKQ_MPSAFE 274.It 275.Xr vnode 9 , 276.Dv VV_MPSAFE 277.It 278.Xr workqueue 9 , 279.Dv WQ_MPSAFE 280.El 281.Pp 282The following 283.Nx 284subsystems are still kernel-locked and need re-engineering to take 285advantage of parallelism on multiprocessor systems: 286.Bl -bullet 287.It 288.Xr ata 4 , 289.Xr atapi 4 , 290.Xr wd 4 291.It 292.Xr video 4 293.It 294.Xr autoconf 9 295.It 296most of the network stack by default, unless the option 297.Dv NET_MPSAFE 298is enabled 299.It 300.No ... 301.El 302.Pp 303All interrupt handlers at 304.Dv IPL_VM , 305or lower 306.Pq Xr spl 9 307run with the kernel lock on most ports. 308.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 309.Sh SEE ALSO 310.Xr locking 9 , 311.Xr mutex 9 , 312.Xr spl 9 313