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.It Dv SX_DUPOK 128Witness should not log messages about duplicate locks being acquired. 129.It Dv SX_NOWITNESS 130Instruct 131.Xr witness 4 132to ignore this lock. 133.It Dv SX_NOPROFILE 134Do not profile this lock. 135.It Dv SX_RECURSE 136Allow threads to recursively acquire exclusive locks for 137.Fa sx . 138.It Dv SX_QUIET 139Do not log any operations for this lock via 140.Xr ktr 4 . 141.It Dv SX_NEW 142If the kernel has been compiled with 143.Cd "options INVARIANTS" , 144.Fn sx_init 145will assert that the 146.Fa sx 147has not been initialized multiple times without intervening calls to 148.Fn sx_destroy 149unless this option is specified. 150.El 151.Pp 152Shared/exclusive locks are destroyed with 153.Fn sx_destroy . 154The lock 155.Fa sx 156must not be locked by any thread when it is destroyed. 157.Pp 158Threads acquire and release a shared lock by calling 159.Fn sx_slock , 160.Fn sx_slock_sig 161or 162.Fn sx_try_slock 163and 164.Fn sx_sunlock 165or 166.Fn sx_unlock . 167Threads acquire and release an exclusive lock by calling 168.Fn sx_xlock , 169.Fn sx_xlock_sig 170or 171.Fn sx_try_xlock 172and 173.Fn sx_xunlock 174or 175.Fn sx_unlock . 176A thread can attempt to upgrade a currently held shared lock to an exclusive 177lock by calling 178.Fn sx_try_upgrade . 179A thread that has an exclusive lock can downgrade it to a shared lock by 180calling 181.Fn sx_downgrade . 182.Pp 183.Fn sx_try_slock 184and 185.Fn sx_try_xlock 186will return 0 if the shared/exclusive lock cannot be acquired immediately; 187otherwise the shared/exclusive lock will be acquired and a non-zero value will 188be returned. 189.Pp 190.Fn sx_try_upgrade 191will return 0 if the shared lock cannot be upgraded to an exclusive lock 192immediately; otherwise the exclusive lock will be acquired and a non-zero value 193will be returned. 194.Pp 195.Fn sx_slock_sig 196and 197.Fn sx_xlock_sig 198do the same as their normal versions but performing an interruptible sleep. 199They return a non-zero value if the sleep has been interrupted by a signal 200or an interrupt, otherwise 0. 201.Pp 202A thread can atomically release a shared/exclusive lock while waiting for an 203event by calling 204.Fn sx_sleep . 205For more details on the parameters to this function, 206see 207.Xr sleep 9 . 208.Pp 209When compiled with 210.Cd "options INVARIANTS" 211and 212.Cd "options INVARIANT_SUPPORT" , 213the 214.Fn sx_assert 215function tests 216.Fa sx 217for the assertions specified in 218.Fa what , 219and panics if they are not met. 220One of the following assertions must be specified: 221.Bl -tag -width ".Dv SA_UNLOCKED" 222.It Dv SA_LOCKED 223Assert that the current thread has either a shared or an exclusive lock on the 224.Vt sx 225lock pointed to by the first argument. 226.It Dv SA_SLOCKED 227Assert that the current thread has a shared lock on the 228.Vt sx 229lock pointed to by 230the first argument. 231.It Dv SA_XLOCKED 232Assert that the current thread has an exclusive lock on the 233.Vt sx 234lock pointed to 235by the first argument. 236.It Dv SA_UNLOCKED 237Assert that the current thread has no lock on the 238.Vt sx 239lock pointed to 240by the first argument. 241.El 242.Pp 243In addition, one of the following optional assertions may be included with 244either an 245.Dv SA_LOCKED , 246.Dv SA_SLOCKED , 247or 248.Dv SA_XLOCKED 249assertion: 250.Bl -tag -width ".Dv SA_NOTRECURSED" 251.It Dv SA_RECURSED 252Assert that the current thread has a recursed lock on 253.Fa sx . 254.It Dv SA_NOTRECURSED 255Assert that the current thread does not have a recursed lock on 256.Fa sx . 257.El 258.Pp 259.Fn sx_xholder 260will return a pointer to the thread which currently holds an exclusive lock on 261.Fa sx . 262If no thread holds an exclusive lock on 263.Fa sx , 264then 265.Dv NULL 266is returned instead. 267.Pp 268.Fn sx_xlocked 269will return non-zero if the current thread holds the exclusive lock; 270otherwise, it will return zero. 271.Pp 272For ease of programming, 273.Fn sx_unlock 274is provided as a macro frontend to the respective functions, 275.Fn sx_sunlock 276and 277.Fn sx_xunlock . 278Algorithms that are aware of what state the lock is in should use either 279of the two specific functions for a minor performance benefit. 280.Pp 281The 282.Fn SX_SYSINIT 283macro is used to generate a call to the 284.Fn sx_sysinit 285routine at system startup in order to initialize a given 286.Fa sx 287lock. 288The parameters are the same as 289.Fn sx_init 290but with an additional argument, 291.Fa name , 292that is used in generating unique variable names for the related 293structures associated with the lock and the sysinit routine. 294The 295.Fn SX_SYSINIT_FLAGS 296macro can similarly be used to initialize a given 297.Fa sx 298lock using 299.Fn sx_init_flags . 300.Pp 301A thread may not hold both a shared lock and an exclusive lock on the same 302lock simultaneously; 303attempting to do so will result in deadlock. 304.Sh CONTEXT 305A thread may hold a shared or exclusive lock on an 306.Nm 307lock while sleeping. 308As a result, an 309.Nm 310lock may not be acquired while holding a mutex. 311Otherwise, if one thread slept while holding an 312.Nm 313lock while another thread blocked on the same 314.Nm 315lock after acquiring a mutex, then the second thread would effectively 316end up sleeping while holding a mutex, which is not allowed. 317.Sh SEE ALSO 318.Xr lock 9 , 319.Xr locking 9 , 320.Xr mutex 9 , 321.Xr panic 9 , 322.Xr rwlock 9 , 323.Xr sema 9 324.Sh BUGS 325A kernel without 326.Dv WITNESS 327cannot assert whether the current thread does or does not hold a shared lock. 328.Dv SA_LOCKED 329and 330.Dv SA_SLOCKED 331can only assert that 332.Em any 333thread holds a shared lock. 334They cannot ensure that the current thread holds a shared lock. 335Further, 336.Dv SA_UNLOCKED 337can only assert that the current thread does not hold an exclusive lock. 338