summaryrefslogtreecommitdiff
path: root/static/freebsd/man9/rmlock.9 4.html
blob: 7120bb56c23bca1294a080d85031156cbc08cc1a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
<table class="head">
  <tr>
    <td class="head-ltitle">RMLOCK(9)</td>
    <td class="head-vol">Kernel Developer's Manual</td>
    <td class="head-rtitle">RMLOCK(9)</td>
  </tr>
</table>
<div class="manual-text">
<section class="Sh">
<h1 class="Sh" id="NAME"><a class="permalink" href="#NAME">NAME</a></h1>
<p class="Pp"><code class="Nm">rmlock</code>, <code class="Nm">rm_init</code>,
    <code class="Nm">rm_init_flags</code>, <code class="Nm">rm_destroy</code>,
    <code class="Nm">rm_rlock</code>, <code class="Nm">rm_try_rlock</code>,
    <code class="Nm">rm_wlock</code>, <code class="Nm">rm_runlock</code>,
    <code class="Nm">rm_wunlock</code>, <code class="Nm">rm_wowned</code>,
    <code class="Nm">rm_sleep</code>, <code class="Nm">rm_assert</code>,
    <code class="Nm">RM_SYSINIT</code>,
    <code class="Nm">RM_SYSINIT_FLAGS</code>, <code class="Nm">rms_init</code>,
    <code class="Nm">rms_destroy</code>, <code class="Nm">rms_rlock</code>,
    <code class="Nm">rms_wlock</code>, <code class="Nm">rms_runlock</code>,
    <code class="Nm">rms_wunlock</code> &#x2014; <span class="Nd">kernel
    reader/writer lock optimized for read-mostly access patterns</span></p>
</section>
<section class="Sh">
<h1 class="Sh" id="SYNOPSIS"><a class="permalink" href="#SYNOPSIS">SYNOPSIS</a></h1>
<p class="Pp"><code class="In">#include
    &lt;<a class="In">sys/param.h</a>&gt;</code>
  <br/>
  <code class="In">#include &lt;<a class="In">sys/lock.h</a>&gt;</code>
  <br/>
  <code class="In">#include &lt;<a class="In">sys/rmlock.h</a>&gt;</code></p>
<p class="Pp"><var class="Ft">void</var>
  <br/>
  <code class="Fn">rm_init</code>(<var class="Fa" style="white-space: nowrap;">struct
    rmlock *rm</var>, <var class="Fa" style="white-space: nowrap;">const char
    *name</var>);</p>
<p class="Pp"><var class="Ft">void</var>
  <br/>
  <code class="Fn">rm_init_flags</code>(<var class="Fa" style="white-space: nowrap;">struct
    rmlock *rm</var>, <var class="Fa" style="white-space: nowrap;">const char
    *name</var>, <var class="Fa" style="white-space: nowrap;">int
  opts</var>);</p>
<p class="Pp"><var class="Ft">void</var>
  <br/>
  <code class="Fn">rm_destroy</code>(<var class="Fa" style="white-space: nowrap;">struct
    rmlock *rm</var>);</p>
<p class="Pp"><var class="Ft">void</var>
  <br/>
  <code class="Fn">rm_rlock</code>(<var class="Fa" style="white-space: nowrap;">struct
    rmlock *rm</var>, <var class="Fa" style="white-space: nowrap;">struct
    rm_priotracker* tracker</var>);</p>
<p class="Pp"><var class="Ft">int</var>
  <br/>
  <code class="Fn">rm_try_rlock</code>(<var class="Fa" style="white-space: nowrap;">struct
    rmlock *rm</var>, <var class="Fa" style="white-space: nowrap;">struct
    rm_priotracker* tracker</var>);</p>
<p class="Pp"><var class="Ft">void</var>
  <br/>
  <code class="Fn">rm_wlock</code>(<var class="Fa" style="white-space: nowrap;">struct
    rmlock *rm</var>);</p>
<p class="Pp"><var class="Ft">void</var>
  <br/>
  <code class="Fn">rm_runlock</code>(<var class="Fa" style="white-space: nowrap;">struct
    rmlock *rm</var>, <var class="Fa" style="white-space: nowrap;">struct
    rm_priotracker* tracker</var>);</p>
<p class="Pp"><var class="Ft">void</var>
  <br/>
  <code class="Fn">rm_wunlock</code>(<var class="Fa" style="white-space: nowrap;">struct
    rmlock *rm</var>);</p>
<p class="Pp"><var class="Ft">int</var>
  <br/>
  <code class="Fn">rm_wowned</code>(<var class="Fa" style="white-space: nowrap;">const
    struct rmlock *rm</var>);</p>
<p class="Pp"><var class="Ft">int</var>
  <br/>
  <code class="Fn">rm_sleep</code>(<var class="Fa" style="white-space: nowrap;">void
    *wchan</var>, <var class="Fa" style="white-space: nowrap;">struct rmlock
    *rm</var>, <var class="Fa" style="white-space: nowrap;">int priority</var>,
    <var class="Fa" style="white-space: nowrap;">const char *wmesg</var>,
    <var class="Fa" style="white-space: nowrap;">int timo</var>);</p>
<p class="Pp">
  <br/>
  <code class="Cd">options INVARIANTS</code>
  <br/>
  <code class="Cd">options INVARIANT_SUPPORT</code>
  <br/>
  <var class="Ft">void</var>
  <br/>
  <code class="Fn">rm_assert</code>(<var class="Fa" style="white-space: nowrap;">struct
    rmlock *rm</var>, <var class="Fa" style="white-space: nowrap;">int
    what</var>);</p>
<p class="Pp"><code class="In">#include
    &lt;<a class="In">sys/kernel.h</a>&gt;</code></p>
<p class="Pp"><code class="Fn">RM_SYSINIT</code>(<var class="Fa" style="white-space: nowrap;">name</var>,
    <var class="Fa" style="white-space: nowrap;">struct rmlock *rm</var>,
    <var class="Fa" style="white-space: nowrap;">const char *desc</var>);</p>
<p class="Pp"><code class="Fn">RM_SYSINIT_FLAGS</code>(<var class="Fa" style="white-space: nowrap;">name</var>,
    <var class="Fa" style="white-space: nowrap;">struct rmlock *rm</var>,
    <var class="Fa" style="white-space: nowrap;">const char *desc</var>,
    <var class="Fa" style="white-space: nowrap;">int flags</var>);</p>
<p class="Pp"><var class="Ft">void</var>
  <br/>
  <code class="Fn">rms_init</code>(<var class="Fa" style="white-space: nowrap;">struct
    rmslock *rms</var>, <var class="Fa" style="white-space: nowrap;">const char
    *name</var>);</p>
<p class="Pp"><var class="Ft">void</var>
  <br/>
  <code class="Fn">rms_destroy</code>(<var class="Fa" style="white-space: nowrap;">struct
    rmslock *rms</var>);</p>
<p class="Pp"><var class="Ft">void</var>
  <br/>
  <code class="Fn">rms_rlock</code>(<var class="Fa" style="white-space: nowrap;">struct
    rmslock *rms</var>);</p>
<p class="Pp"><var class="Ft">void</var>
  <br/>
  <code class="Fn">rms_wlock</code>(<var class="Fa" style="white-space: nowrap;">struct
    rmslock *rms</var>);</p>
<p class="Pp"><var class="Ft">void</var>
  <br/>
  <code class="Fn">rms_runlock</code>(<var class="Fa" style="white-space: nowrap;">struct
    rmslock *rms</var>);</p>
<p class="Pp"><var class="Ft">void</var>
  <br/>
  <code class="Fn">rms_wunlock</code>(<var class="Fa" style="white-space: nowrap;">struct
    rmslock *rms</var>);</p>
</section>
<section class="Sh">
<h1 class="Sh" id="DESCRIPTION"><a class="permalink" href="#DESCRIPTION">DESCRIPTION</a></h1>
<p class="Pp">Read-mostly locks allow shared access to protected data by
    multiple threads, or exclusive access by a single thread. The threads with
    shared access are known as
    <a class="permalink" href="#readers"><i class="Em" id="readers">readers</i></a>
    since they only read the protected data. A thread with exclusive access is
    known as a
    <a class="permalink" href="#writer"><i class="Em" id="writer">writer</i></a>
    since it can modify protected data.</p>
<p class="Pp">Read-mostly locks are designed to be efficient for locks almost
    exclusively used as reader locks and as such should be used for protecting
    data that rarely changes. Acquiring an exclusive lock after the lock has
    been locked for shared access is an expensive operation.</p>
<p class="Pp" id="rm_rlock">Normal read-mostly locks are similar to
    <a class="Xr">rwlock(9)</a> locks and follow the same lock ordering rules as
    <a class="Xr">rwlock(9)</a> locks. Read-mostly locks have full priority
    propagation like mutexes. Unlike <a class="Xr">rwlock(9)</a>, read-mostly
    locks propagate priority to both readers and writers. This is implemented
    via the <var class="Va">rm_priotracker</var> structure argument supplied to
    <a class="permalink" href="#rm_rlock"><code class="Fn">rm_rlock</code></a>()
    and
    <a class="permalink" href="#rm_runlock"><code class="Fn" id="rm_runlock">rm_runlock</code></a>().
    Readers can recurse if the lock is initialized with the
    <code class="Dv">RM_RECURSE</code> option; however, writers are never
    allowed to recurse.</p>
<p class="Pp" id="rm_init_flags">Sleeping for writers can be allowed by passing
    <code class="Dv">RM_SLEEPABLE</code> to
    <a class="permalink" href="#rm_init_flags"><code class="Fn">rm_init_flags</code></a>().
    It changes lock ordering rules to the same as for <a class="Xr">sx(9)</a>
    locks. They do not propagate priority to writers, but they do propagate
    priority to readers. Note that readers are not permitted to sleep regardless
    of the flag.</p>
<p class="Pp" id="rms_init">Sleepable read-mostly locks (created with
    <a class="permalink" href="#rms_init"><code class="Fn">rms_init</code></a>())
    allow sleeping for both readers and writers, but don't do priority
    propagation for either. They follow <a class="Xr">sx(9)</a> lock
  ordering.</p>
<section class="Ss">
<h2 class="Ss" id="Macros_and_Functions"><a class="permalink" href="#Macros_and_Functions">Macros
  and Functions</a></h2>
<dl class="Bl-tag">
  <dt id="rm_init"><a class="permalink" href="#rm_init"><code class="Fn">rm_init</code></a>(<var class="Fa">struct
    rmlock *rm</var>, <var class="Fa">const char *name</var>)</dt>
  <dd>Initialize the read-mostly lock <var class="Fa">rm</var>. The
      <var class="Fa">name</var> description is used solely for debugging
      purposes. This function must be called before any other operations on the
      lock.</dd>
  <dt><code class="Fn">rm_init_flags</code>(<var class="Fa">struct rmlock
    *rm</var>, <var class="Fa">const char *name</var>, <var class="Fa">int
    opts</var>)</dt>
  <dd>Similar to <code class="Fn">rm_init</code>(), initialize the read-mostly
      lock <var class="Fa">rm</var> with a set of optional flags. The
      <var class="Fa">opts</var> arguments contains one or more of the following
      flags:
    <dl class="Bl-tag">
      <dt id="RM_NOWITNESS"><a class="permalink" href="#RM_NOWITNESS"><code class="Dv">RM_NOWITNESS</code></a></dt>
      <dd>Instruct <a class="Xr">witness(4)</a> to ignore this lock.</dd>
      <dt id="RM_RECURSE"><a class="permalink" href="#RM_RECURSE"><code class="Dv">RM_RECURSE</code></a></dt>
      <dd>Allow threads to recursively acquire shared locks for
          <var class="Fa">rm</var>.</dd>
      <dt id="RM_SLEEPABLE"><a class="permalink" href="#RM_SLEEPABLE"><code class="Dv">RM_SLEEPABLE</code></a></dt>
      <dd>Create a sleepable read-mostly lock.</dd>
      <dt id="RM_NEW"><a class="permalink" href="#RM_NEW"><code class="Dv">RM_NEW</code></a></dt>
      <dd>If the kernel has been compiled with <code class="Cd">option
          INVARIANTS</code>, <code class="Fn">rm_init_flags</code>() will assert
          that the <var class="Fa">rm</var> has not been initialized multiple
          times without intervening calls to
          <a class="permalink" href="#rm_destroy"><code class="Fn" id="rm_destroy">rm_destroy</code></a>()
          unless this option is specified.</dd>
      <dt id="RM_DUPOK"><a class="permalink" href="#RM_DUPOK"><code class="Dv">RM_DUPOK</code></a></dt>
      <dd><a class="Xr">witness(4)</a> should not log messages about duplicate
          locks being acquired.</dd>
    </dl>
  </dd>
  <dt><code class="Fn">rm_rlock</code>(<var class="Fa">struct rmlock *rm</var>,
    <var class="Fa">struct rm_priotracker* tracker</var>)</dt>
  <dd>Lock <var class="Fa">rm</var> as a reader using
      <var class="Fa">tracker</var> to track read owners of a lock for priority
      propagation. This data structure is only used internally by
      <code class="Nm">rmlock</code> and must persist until
      <code class="Fn">rm_runlock</code>() has been called. This data structure
      can be allocated on the stack since readers cannot sleep. If any thread
      holds this lock exclusively, the current thread blocks, and its priority
      is propagated to the exclusive holder. If the lock was initialized with
      the <code class="Dv">RM_RECURSE</code> option the
      <code class="Fn">rm_rlock</code>() function can be called when the current
      thread has already acquired reader access on
    <var class="Fa">rm</var>.</dd>
  <dt id="rm_try_rlock"><a class="permalink" href="#rm_try_rlock"><code class="Fn">rm_try_rlock</code></a>(<var class="Fa">struct
    rmlock *rm</var>, <var class="Fa">struct rm_priotracker* tracker</var>)</dt>
  <dd>Try to lock <var class="Fa">rm</var> as a reader.
      <code class="Fn">rm_try_rlock</code>() will return 0 if the lock cannot be
      acquired immediately; otherwise, the lock will be acquired and a non-zero
      value will be returned. Note that <code class="Fn">rm_try_rlock</code>()
      may fail even while the lock is not currently held by a writer. If the
      lock was initialized with the <code class="Dv">RM_RECURSE</code> option,
      <code class="Fn">rm_try_rlock</code>() will succeed if the current thread
      has already acquired reader access.</dd>
  <dt id="rm_wlock"><a class="permalink" href="#rm_wlock"><code class="Fn">rm_wlock</code></a>(<var class="Fa">struct
    rmlock *rm</var>)</dt>
  <dd>Lock <var class="Fa">rm</var> as a writer. If there are any shared owners
      of the lock, the current thread blocks. The
      <code class="Fn">rm_wlock</code>() function cannot be called
    recursively.</dd>
  <dt><code class="Fn">rm_runlock</code>(<var class="Fa">struct rmlock
    *rm</var>, <var class="Fa">struct rm_priotracker* tracker</var>)</dt>
  <dd>This function releases a shared lock previously acquired by
      <code class="Fn">rm_rlock</code>(). The <var class="Fa">tracker</var>
      argument must match the <var class="Fa">tracker</var> argument used for
      acquiring the shared lock</dd>
  <dt id="rm_wunlock"><a class="permalink" href="#rm_wunlock"><code class="Fn">rm_wunlock</code></a>(<var class="Fa">struct
    rmlock *rm</var>)</dt>
  <dd>This function releases an exclusive lock previously acquired by
      <code class="Fn">rm_wlock</code>().</dd>
  <dt><code class="Fn">rm_destroy</code>(<var class="Fa">struct rmlock
    *rm</var>)</dt>
  <dd>This functions destroys a lock previously initialized with
      <code class="Fn">rm_init</code>(). The <var class="Fa">rm</var> lock must
      be unlocked.</dd>
  <dt id="rm_wowned"><a class="permalink" href="#rm_wowned"><code class="Fn">rm_wowned</code></a>(<var class="Fa">const
    struct rmlock *rm</var>)</dt>
  <dd>This function returns a non-zero value if the current thread owns an
      exclusive lock on <var class="Fa">rm</var>.</dd>
  <dt id="rm_sleep"><a class="permalink" href="#rm_sleep"><code class="Fn">rm_sleep</code></a>(<var class="Fa">void
    *wchan</var>, <var class="Fa">struct rmlock *rm</var>, <var class="Fa">int
    priority</var>, <var class="Fa">const char *wmesg</var>, <var class="Fa">int
    timo</var>)</dt>
  <dd>This function atomically releases <var class="Fa">rm</var> while waiting
      for an event. The <var class="Fa">rm</var> lock must be exclusively
      locked. For more details on the parameters to this function, see
      <a class="Xr">sleep(9)</a>.</dd>
  <dt id="rm_assert"><a class="permalink" href="#rm_assert"><code class="Fn">rm_assert</code></a>(<var class="Fa">struct
    rmlock *rm</var>, <var class="Fa">int what</var>)</dt>
  <dd>This function asserts that the <var class="Fa">rm</var> lock is in the
      state specified by <var class="Fa">what</var>. If the assertions are not
      true and the kernel is compiled with <code class="Cd">options
      INVARIANTS</code> and <code class="Cd">options INVARIANT_SUPPORT</code>,
      the kernel will panic. Currently the following base assertions are
      supported:
    <dl class="Bl-tag">
      <dt id="RA_LOCKED"><a class="permalink" href="#RA_LOCKED"><code class="Dv">RA_LOCKED</code></a></dt>
      <dd>Assert that current thread holds either a shared or exclusive lock of
          <var class="Fa">rm</var>.</dd>
      <dt id="RA_RLOCKED"><a class="permalink" href="#RA_RLOCKED"><code class="Dv">RA_RLOCKED</code></a></dt>
      <dd>Assert that current thread holds a shared lock of
          <var class="Fa">rm</var>.</dd>
      <dt id="RA_WLOCKED"><a class="permalink" href="#RA_WLOCKED"><code class="Dv">RA_WLOCKED</code></a></dt>
      <dd>Assert that current thread holds an exclusive lock of
          <var class="Fa">rm</var>.</dd>
      <dt id="RA_UNLOCKED"><a class="permalink" href="#RA_UNLOCKED"><code class="Dv">RA_UNLOCKED</code></a></dt>
      <dd>Assert that current thread holds neither a shared nor exclusive lock
          of <var class="Fa">rm</var>.</dd>
    </dl>
    <p class="Pp">In addition, one of the following optional flags may be
        specified with <code class="Dv">RA_LOCKED</code>,
        <code class="Dv">RA_RLOCKED</code>, or
        <code class="Dv">RA_WLOCKED</code>:</p>
    <dl class="Bl-tag">
      <dt id="RA_RECURSED"><a class="permalink" href="#RA_RECURSED"><code class="Dv">RA_RECURSED</code></a></dt>
      <dd>Assert that the current thread holds a recursive lock of
          <var class="Fa">rm</var>.</dd>
      <dt id="RA_NOTRECURSED"><a class="permalink" href="#RA_NOTRECURSED"><code class="Dv">RA_NOTRECURSED</code></a></dt>
      <dd>Assert that the current thread does not hold a recursive lock of
          <var class="Fa">rm</var>.</dd>
    </dl>
  </dd>
</dl>
<dl class="Bl-tag">
  <dt id="rms_init~2"><a class="permalink" href="#rms_init~2"><code class="Fn">rms_init</code></a>(<var class="Fa">struct
    rmslock *rms</var>, <var class="Fa">const char *name</var>)</dt>
  <dd>Initialize the sleepable read-mostly lock <var class="Fa">rms</var>. The
      <var class="Fa">name</var> description is used as
      <var class="Fa">wmesg</var> parameter to the <a class="Xr">msleep(9)</a>
      routine. This function must be called before any other operations on the
      lock.</dd>
  <dt id="rms_rlock"><a class="permalink" href="#rms_rlock"><code class="Fn">rms_rlock</code></a>(<var class="Fa">struct
    rmlock *rm</var>)</dt>
  <dd>Lock <var class="Fa">rms</var> as a reader. If any thread holds this lock
      exclusively, the current thread blocks.</dd>
  <dt id="rms_wlock"><a class="permalink" href="#rms_wlock"><code class="Fn">rms_wlock</code></a>(<var class="Fa">struct
    rmslock *rms</var>)</dt>
  <dd>Lock <var class="Fa">rms</var> as a writer. If the lock is already taken,
      the current thread blocks. The <code class="Fn">rms_wlock</code>()
      function cannot be called recursively.</dd>
  <dt id="rms_runlock"><a class="permalink" href="#rms_runlock"><code class="Fn">rms_runlock</code></a>(<var class="Fa">struct
    rmslock *rms</var>)</dt>
  <dd>This function releases a shared lock previously acquired by
      <code class="Fn">rms_rlock</code>().</dd>
  <dt id="rms_wunlock"><a class="permalink" href="#rms_wunlock"><code class="Fn">rms_wunlock</code></a>(<var class="Fa">struct
    rmslock *rms</var>)</dt>
  <dd>This function releases an exclusive lock previously acquired by
      <code class="Fn">rms_wlock</code>().</dd>
  <dt id="rms_destroy"><a class="permalink" href="#rms_destroy"><code class="Fn">rms_destroy</code></a>(<var class="Fa">struct
    rmslock *rms</var>)</dt>
  <dd>This functions destroys a lock previously initialized with
      <code class="Fn">rms_init</code>(). The <var class="Fa">rms</var> lock
      must be unlocked.</dd>
</dl>
</section>
</section>
<section class="Sh">
<h1 class="Sh" id="SEE_ALSO"><a class="permalink" href="#SEE_ALSO">SEE
  ALSO</a></h1>
<p class="Pp"><a class="Xr">locking(9)</a>, <a class="Xr">mutex(9)</a>,
    <a class="Xr">panic(9)</a>, <a class="Xr">rwlock(9)</a>,
    <a class="Xr">sema(9)</a>, <a class="Xr">sleep(9)</a>,
    <a class="Xr">sx(9)</a></p>
</section>
<section class="Sh">
<h1 class="Sh" id="HISTORY"><a class="permalink" href="#HISTORY">HISTORY</a></h1>
<p class="Pp">These functions appeared in <span class="Ux">FreeBSD
  7.0</span>.</p>
</section>
<section class="Sh">
<h1 class="Sh" id="AUTHORS"><a class="permalink" href="#AUTHORS">AUTHORS</a></h1>
<p class="Pp">The <code class="Nm">rmlock</code> facility was written by
    <span class="An">Stephan Uphoff</span>. This manual page was written by
    <span class="An">Gleb Smirnoff</span> for rwlock and modified to reflect
    rmlock by <span class="An">Stephan Uphoff</span>.</p>
</section>
<section class="Sh">
<h1 class="Sh" id="BUGS"><a class="permalink" href="#BUGS">BUGS</a></h1>
<p class="Pp">The <code class="Nm">rmlock</code> implementation is currently not
    optimized for single processor systems.</p>
<p class="Pp"><code class="Fn">rm_try_rlock</code>() can fail transiently even
    when there is no writer, while another reader updates the state on the local
    CPU.</p>
<p class="Pp">The <code class="Nm">rmlock</code> implementation uses a single
    per CPU list shared by all rmlocks in the system. If rmlocks become popular,
    hashing to multiple per CPU queues may be needed to speed up the writer lock
    process.</p>
</section>
</div>
<table class="foot">
  <tr>
    <td class="foot-date">April 12, 2021</td>
    <td class="foot-os">FreeBSD 15.0</td>
  </tr>
</table>