1.\" Copyright (c) 2007 Stephan Uphoff <ups@FreeBSD.org> 2.\" Copyright (c) 2006 Gleb Smirnoff <glebius@FreeBSD.org> 3.\" All rights reserved. 4.\" 5.\" Redistribution and use in source and binary forms, with or without 6.\" modification, are permitted provided that the following conditions 7.\" are met: 8.\" 1. Redistributions of source code must retain the above copyright 9.\" notice, this list of conditions and the following disclaimer. 10.\" 2. Redistributions in binary form must reproduce the above copyright 11.\" notice, this list of conditions and the following disclaimer in the 12.\" documentation and/or other materials provided with the distribution. 13.\" 14.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24.\" SUCH DAMAGE. 25.\" 26.\" $FreeBSD$ 27.\" 28.\" Based on rwlock.9 man page 29.Dd June 25, 2013 30.Dt RMLOCK 9 31.Os 32.Sh NAME 33.Nm rmlock , 34.Nm rm_init , 35.Nm rm_init_flags , 36.Nm rm_destroy , 37.Nm rm_rlock , 38.Nm rm_try_rlock , 39.Nm rm_wlock , 40.Nm rm_runlock , 41.Nm rm_wunlock , 42.Nm rm_wowned , 43.Nm rm_sleep , 44.Nm rm_assert , 45.Nm RM_SYSINIT 46.Nd kernel reader/writer lock optimized for read-mostly access patterns 47.Sh SYNOPSIS 48.In sys/param.h 49.In sys/lock.h 50.In sys/rmlock.h 51.Ft void 52.Fn rm_init "struct rmlock *rm" "const char *name" 53.Ft void 54.Fn rm_init_flags "struct rmlock *rm" "const char *name" "int opts" 55.Ft void 56.Fn rm_destroy "struct rmlock *rm" 57.Ft void 58.Fn rm_rlock "struct rmlock *rm" "struct rm_priotracker* tracker" 59.Ft int 60.Fn rm_try_rlock "struct rmlock *rm" "struct rm_priotracker* tracker" 61.Ft void 62.Fn rm_wlock "struct rmlock *rm" 63.Ft void 64.Fn rm_runlock "struct rmlock *rm" "struct rm_priotracker* tracker" 65.Ft void 66.Fn rm_wunlock "struct rmlock *rm" 67.Ft int 68.Fn rm_wowned "const struct rmlock *rm" 69.Ft int 70.Fn rm_sleep "void *wchan" "struct rmlock *rm" "int priority" "const char *wmesg" "int timo" 71.Pp 72.Cd "options INVARIANTS" 73.Cd "options INVARIANT_SUPPORT" 74.Ft void 75.Fn rm_assert "struct rmlock *rm" "int what" 76.In sys/kernel.h 77.Fn RM_SYSINIT "name" "struct rmlock *rm" "const char *desc" "int opts" 78.Sh DESCRIPTION 79Read-mostly locks allow shared access to protected data by multiple threads, 80or exclusive access by a single thread. 81The threads with shared access are known as 82.Em readers 83since they only read the protected data. 84A thread with exclusive access is known as a 85.Em writer 86since it can modify protected data. 87.Pp 88Read-mostly locks are designed to be efficient for locks almost exclusively 89used as reader locks and as such should be used for protecting data that 90rarely changes. 91Acquiring an exclusive lock after the lock has been locked for shared access 92is an expensive operation. 93.Pp 94Normal read-mostly locks are similar to 95.Xr rwlock 9 96locks and follow the same lock ordering rules as 97.Xr rwlock 9 98locks. 99Read-mostly locks have full priority propagation like mutexes. 100Unlike 101.Xr rwlock 9 , 102read-mostly locks propagate priority to both readers and writers. 103This is implemented via the 104.Va rm_priotracker 105structure argument supplied to 106.Fn rm_rlock 107and 108.Fn rm_runlock . 109Readers can recurse if the lock is initialized with the 110.Dv RM_RECURSE 111option; 112however, writers are never allowed to recurse. 113.Pp 114Sleepable read-mostly locks are created by passing 115.Dv RM_SLEEPABLE 116to 117.Fn rm_init_flags . 118Unlike normal read-mostly locks, 119sleepable read-mostly locks follow the same lock ordering rules as 120.Xr sx 9 121locks. 122Sleepable read-mostly locks do not propagate priority to writers, 123but they do propagate priority to readers. 124Writers are permitted to sleep while holding a read-mostly lock, 125but readers are not. 126Unlike other sleepable locks such as 127.Xr sx 9 128locks, 129readers must use try operations on other sleepable locks to avoid sleeping. 130.Ss Macros and Functions 131.Bl -tag -width indent 132.It Fn rm_init "struct rmlock *rm" "const char *name" 133Initialize the read-mostly lock 134.Fa rm . 135The 136.Fa name 137description is used solely for debugging purposes. 138This function must be called before any other operations 139on the lock. 140.It Fn rm_init_flags "struct rmlock *rm" "const char *name" "int opts" 141Similar to 142.Fn rm_init , 143initialize the read-mostly lock 144.Fa rm 145with a set of optional flags. 146The 147.Fa opts 148arguments contains one or more of the following flags: 149.Bl -tag -width ".Dv RM_NOWITNESS" 150.It Dv RM_NOWITNESS 151Instruct 152.Xr witness 4 153to ignore this lock. 154.It Dv RM_RECURSE 155Allow threads to recursively acquire shared locks for 156.Fa rm . 157.It Dv RM_SLEEPABLE 158Create a sleepable read-mostly lock. 159.El 160.It Fn rm_rlock "struct rmlock *rm" "struct rm_priotracker* tracker" 161Lock 162.Fa rm 163as a reader using 164.Fa tracker 165to track read owners of a lock for priority propagation. 166This data structure is only used internally by 167.Nm 168and must persist until 169.Fn rm_runlock 170has been called. 171This data structure can be allocated on the stack since 172readers cannot sleep. 173If any thread holds this lock exclusively, the current thread blocks, 174and its priority is propagated to the exclusive holder. 175If the lock was initialized with the 176.Dv RM_RECURSE 177option the 178.Fn rm_rlock 179function can be called when the current thread has already acquired reader 180access on 181.Fa rm . 182.It Fn rm_try_rlock "struct rmlock *rm" "struct rm_priotracker* tracker" 183Try to lock 184.Fa rm 185as a reader. 186.Fn rm_try_rlock 187will return 0 if the lock cannot be acquired immediately; 188otherwise, 189the lock will be acquired and a non-zero value will be returned. 190Note that 191.Fn rm_try_rlock 192may fail even while the lock is not currently held by a writer. 193If the lock was initialized with the 194.Dv RM_RECURSE 195option, 196.Fn rm_try_rlock 197will succeed if the current thread has already acquired reader access. 198.It Fn rm_wlock "struct rmlock *rm" 199Lock 200.Fa rm 201as a writer. 202If there are any shared owners of the lock, the current thread blocks. 203The 204.Fn rm_wlock 205function cannot be called recursively. 206.It Fn rm_runlock "struct rmlock *rm" "struct rm_priotracker* tracker" 207This function releases a shared lock previously acquired by 208.Fn rm_rlock . 209The 210.Fa tracker 211argument must match the 212.Fa tracker 213argument used for acquiring the shared lock 214.It Fn rm_wunlock "struct rmlock *rm" 215This function releases an exclusive lock previously acquired by 216.Fn rm_wlock . 217.It Fn rm_destroy "struct rmlock *rm" 218This functions destroys a lock previously initialized with 219.Fn rm_init . 220The 221.Fa rm 222lock must be unlocked. 223.It Fn rm_wowned "const struct rmlock *rm" 224This function returns a non-zero value if the current thread owns an 225exclusive lock on 226.Fa rm . 227.It Fn rm_sleep "void *wchan" "struct rmlock *rm" "int priority" "const char *wmesg" "int timo" 228This function atomically releases 229.Fa rm 230while waiting for an event. 231The 232.Fa rm 233lock must be exclusively locked. 234For more details on the parameters to this function, 235see 236.Xr sleep 9 . 237.It Fn rm_assert "struct rmlock *rm" "int what" 238This function asserts that the 239.Fa rm 240lock is in the state specified by 241.Fa what . 242If the assertions are not true and the kernel is compiled with 243.Cd "options INVARIANTS" 244and 245.Cd "options INVARIANT_SUPPORT" , 246the kernel will panic. 247Currently the following base assertions are supported: 248.Bl -tag -width ".Dv RA_UNLOCKED" 249.It Dv RA_LOCKED 250Assert that current thread holds either a shared or exclusive lock 251of 252.Fa rm . 253.It Dv RA_RLOCKED 254Assert that current thread holds a shared lock of 255.Fa rm . 256.It Dv RA_WLOCKED 257Assert that current thread holds an exclusive lock of 258.Fa rm . 259.It Dv RA_UNLOCKED 260Assert that current thread holds neither a shared nor exclusive lock of 261.Fa rm . 262.El 263.Pp 264In addition, one of the following optional flags may be specified with 265.Dv RA_LOCKED , 266.Dv RA_RLOCKED , 267or 268.Dv RA_WLOCKED : 269.Bl -tag -width ".Dv RA_NOTRECURSED" 270.It Dv RA_RECURSED 271Assert that the current thread holds a recursive lock of 272.Fa rm . 273.It Dv RA_NOTRECURSED 274Assert that the current thread does not hold a recursive lock of 275.Fa rm . 276.El 277.El 278.Sh SEE ALSO 279.Xr locking 9 , 280.Xr mutex 9 , 281.Xr panic 9 , 282.Xr rwlock 9 , 283.Xr sleep 9 , 284.Xr sema 9 , 285.Xr sx 9 286.Sh HISTORY 287These 288functions appeared in 289.Fx 7.0 . 290.Sh AUTHORS 291.An -nosplit 292The 293.Nm 294facility was written by 295.An "Stephan Uphoff" . 296This manual page was written by 297.An "Gleb Smirnoff" 298for rwlock and modified to reflect rmlock by 299.An "Stephan Uphoff" . 300.Sh BUGS 301The 302.Nm 303implementation is currently not optimized for single processor systems. 304.Pp 305.Fn rm_try_rlock 306can fail transiently even when there is no writer, while another reader 307updates the state on the local CPU. 308.Pp 309The 310.Nm 311implementation uses a single per CPU list shared by all 312rmlocks in the system. 313If rmlocks become popular, hashing to multiple per CPU queues may 314be needed to speed up the writer lock process. 315