1.\" 2.\" Copyright (C) 2001 Jason Evans <jasone@FreeBSD.org>. All rights reserved. 3.\" 4.\" Redistribution and use in source and binary forms, with or without 5.\" modification, are permitted provided that the following conditions 6.\" are met: 7.\" 1. Redistributions of source code must retain the above copyright 8.\" notice(s), this list of conditions and the following disclaimer as 9.\" the first lines of this file unmodified other than the possible 10.\" addition of one or more copyright notices. 11.\" 2. Redistributions in binary form must reproduce the above copyright 12.\" notice(s), 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 COPYRIGHT HOLDER(S) ``AS IS'' AND ANY 16.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18.\" DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 19.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22.\" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 25.\" DAMAGE. 26.\" 27.\" $FreeBSD$ 28.\" 29.Dd November 11, 2017 30.Dt SX 9 31.Os 32.Sh NAME 33.Nm sx , 34.Nm sx_init , 35.Nm sx_init_flags , 36.Nm sx_destroy , 37.Nm sx_slock , 38.Nm sx_xlock , 39.Nm sx_slock_sig , 40.Nm sx_xlock_sig , 41.Nm sx_try_slock , 42.Nm sx_try_xlock , 43.Nm sx_sunlock , 44.Nm sx_xunlock , 45.Nm sx_unlock , 46.Nm sx_try_upgrade , 47.Nm sx_downgrade , 48.Nm sx_sleep , 49.Nm sx_xholder , 50.Nm sx_xlocked , 51.Nm sx_assert , 52.Nm SX_SYSINIT , 53.Nm SX_SYSINIT_FLAGS 54.Nd kernel shared/exclusive lock 55.Sh SYNOPSIS 56.In sys/param.h 57.In sys/lock.h 58.In sys/sx.h 59.Ft void 60.Fn sx_init "struct sx *sx" "const char *description" 61.Ft void 62.Fn sx_init_flags "struct sx *sx" "const char *description" "int opts" 63.Ft void 64.Fn sx_destroy "struct sx *sx" 65.Ft void 66.Fn sx_slock "struct sx *sx" 67.Ft void 68.Fn sx_xlock "struct sx *sx" 69.Ft int 70.Fn sx_slock_sig "struct sx *sx" 71.Ft int 72.Fn sx_xlock_sig "struct sx *sx" 73.Ft int 74.Fn sx_try_slock "struct sx *sx" 75.Ft int 76.Fn sx_try_xlock "struct sx *sx" 77.Ft void 78.Fn sx_sunlock "struct sx *sx" 79.Ft void 80.Fn sx_xunlock "struct sx *sx" 81.Ft void 82.Fn sx_unlock "struct sx *sx" 83.Ft int 84.Fn sx_try_upgrade "struct sx *sx" 85.Ft void 86.Fn sx_downgrade "struct sx *sx" 87.Ft int 88.Fn sx_sleep "void *chan" "struct sx *sx" "int priority" "const char *wmesg" "int timo" 89.Ft "struct thread *" 90.Fn sx_xholder "struct sx *sx" 91.Ft int 92.Fn sx_xlocked "const struct sx *sx" 93.Pp 94.Cd "options INVARIANTS" 95.Cd "options INVARIANT_SUPPORT" 96.Ft void 97.Fn sx_assert "const struct sx *sx" "int what" 98.In sys/kernel.h 99.Fn SX_SYSINIT "name" "struct sx *sx" "const char *desc" 100.Fn SX_SYSINIT_FLAGS "name" "struct sx *sx" "const char *desc" "int flags" 101.Sh DESCRIPTION 102Shared/exclusive locks are used to protect data that are read far more often 103than they are written. 104Shared/exclusive locks do not implement priority propagation like mutexes and 105reader/writer locks to prevent priority inversions, so 106shared/exclusive locks should be used prudently. 107.Pp 108Shared/exclusive locks are created with either 109.Fn sx_init 110or 111.Fn sx_init_flags 112where 113.Fa sx 114is a pointer to space for a 115.Vt struct sx , 116and 117.Fa description 118is a pointer to a null-terminated character string that describes the 119shared/exclusive lock. 120The 121.Fa opts 122argument to 123.Fn sx_init_flags 124specifies a set of optional flags to alter the behavior of 125.Fa sx . 126It contains one or more of the following flags: 127.Bl -tag -width SX_NOWITNESS 128.It Dv SX_DUPOK 129Witness should not log messages about duplicate locks being acquired. 130.It Dv SX_NOWITNESS 131Instruct 132.Xr witness 4 133to ignore this lock. 134.It Dv SX_NOPROFILE 135Do not profile this lock. 136.It Dv SX_RECURSE 137Allow threads to recursively acquire exclusive locks for 138.Fa sx . 139.It Dv SX_QUIET 140Do not log any operations for this lock via 141.Xr ktr 4 . 142.It Dv SX_NEW 143If the kernel has been compiled with 144.Cd "options INVARIANTS" , 145.Fn sx_init 146will assert that the 147.Fa sx 148has not been initialized multiple times without intervening calls to 149.Fn sx_destroy 150unless this option is specified. 151.El 152.Pp 153Shared/exclusive locks are destroyed with 154.Fn sx_destroy . 155The lock 156.Fa sx 157must not be locked by any thread when it is destroyed. 158.Pp 159Threads acquire and release a shared lock by calling 160.Fn sx_slock , 161.Fn sx_slock_sig 162or 163.Fn sx_try_slock 164and 165.Fn sx_sunlock 166or 167.Fn sx_unlock . 168Threads acquire and release an exclusive lock by calling 169.Fn sx_xlock , 170.Fn sx_xlock_sig 171or 172.Fn sx_try_xlock 173and 174.Fn sx_xunlock 175or 176.Fn sx_unlock . 177A thread can attempt to upgrade a currently held shared lock to an exclusive 178lock by calling 179.Fn sx_try_upgrade . 180A thread that has an exclusive lock can downgrade it to a shared lock by 181calling 182.Fn sx_downgrade . 183.Pp 184.Fn sx_try_slock 185and 186.Fn sx_try_xlock 187will return 0 if the shared/exclusive lock cannot be acquired immediately; 188otherwise the shared/exclusive lock will be acquired and a non-zero value will 189be returned. 190.Pp 191.Fn sx_try_upgrade 192will return 0 if the shared lock cannot be upgraded to an exclusive lock 193immediately; otherwise the exclusive lock will be acquired and a non-zero value 194will be returned. 195.Pp 196.Fn sx_slock_sig 197and 198.Fn sx_xlock_sig 199do the same as their normal versions but performing an interruptible sleep. 200They return a non-zero value if the sleep has been interrupted by a signal 201or an interrupt, otherwise 0. 202.Pp 203A thread can atomically release a shared/exclusive lock while waiting for an 204event by calling 205.Fn sx_sleep . 206For more details on the parameters to this function, 207see 208.Xr sleep 9 . 209.Pp 210When compiled with 211.Cd "options INVARIANTS" 212and 213.Cd "options INVARIANT_SUPPORT" , 214the 215.Fn sx_assert 216function tests 217.Fa sx 218for the assertions specified in 219.Fa what , 220and panics if they are not met. 221One of the following assertions must be specified: 222.Bl -tag -width ".Dv SA_UNLOCKED" 223.It Dv SA_LOCKED 224Assert that the current thread has either a shared or an exclusive lock on the 225.Vt sx 226lock pointed to by the first argument. 227.It Dv SA_SLOCKED 228Assert that the current thread has a shared lock on the 229.Vt sx 230lock pointed to by 231the first argument. 232.It Dv SA_XLOCKED 233Assert that the current thread has an exclusive lock on the 234.Vt sx 235lock pointed to 236by the first argument. 237.It Dv SA_UNLOCKED 238Assert that the current thread has no lock on the 239.Vt sx 240lock pointed to 241by the first argument. 242.El 243.Pp 244In addition, one of the following optional assertions may be included with 245either an 246.Dv SA_LOCKED , 247.Dv SA_SLOCKED , 248or 249.Dv SA_XLOCKED 250assertion: 251.Bl -tag -width ".Dv SA_NOTRECURSED" 252.It Dv SA_RECURSED 253Assert that the current thread has a recursed lock on 254.Fa sx . 255.It Dv SA_NOTRECURSED 256Assert that the current thread does not have a recursed lock on 257.Fa sx . 258.El 259.Pp 260.Fn sx_xholder 261will return a pointer to the thread which currently holds an exclusive lock on 262.Fa sx . 263If no thread holds an exclusive lock on 264.Fa sx , 265then 266.Dv NULL 267is returned instead. 268.Pp 269.Fn sx_xlocked 270will return non-zero if the current thread holds the exclusive lock; 271otherwise, it will return zero. 272.Pp 273For ease of programming, 274.Fn sx_unlock 275is provided as a macro frontend to the respective functions, 276.Fn sx_sunlock 277and 278.Fn sx_xunlock . 279Algorithms that are aware of what state the lock is in should use either 280of the two specific functions for a minor performance benefit. 281.Pp 282The 283.Fn SX_SYSINIT 284macro is used to generate a call to the 285.Fn sx_sysinit 286routine at system startup in order to initialize a given 287.Fa sx 288lock. 289The parameters are the same as 290.Fn sx_init 291but with an additional argument, 292.Fa name , 293that is used in generating unique variable names for the related 294structures associated with the lock and the sysinit routine. 295The 296.Fn SX_SYSINIT_FLAGS 297macro can similarly be used to initialize a given 298.Fa sx 299lock using 300.Fn sx_init_flags . 301.Pp 302A thread may not hold both a shared lock and an exclusive lock on the same 303lock simultaneously; 304attempting to do so will result in deadlock. 305.Sh CONTEXT 306A thread may hold a shared or exclusive lock on an 307.Nm 308lock while sleeping. 309As a result, an 310.Nm 311lock may not be acquired while holding a mutex. 312Otherwise, if one thread slept while holding an 313.Nm 314lock while another thread blocked on the same 315.Nm 316lock after acquiring a mutex, then the second thread would effectively 317end up sleeping while holding a mutex, which is not allowed. 318.Sh SEE ALSO 319.Xr lock 9 , 320.Xr locking 9 , 321.Xr mutex 9 , 322.Xr panic 9 , 323.Xr rwlock 9 , 324.Xr sema 9 325.Sh BUGS 326A kernel without 327.Dv WITNESS 328cannot assert whether the current thread does or does not hold a shared lock. 329.Dv SA_LOCKED 330and 331.Dv SA_SLOCKED 332can only assert that 333.Em any 334thread holds a shared lock. 335They cannot ensure that the current thread holds a shared lock. 336Further, 337.Dv SA_UNLOCKED 338can only assert that the current thread does not hold an exclusive lock. 339