xref: /freebsd/sys/kern/kern_rmlock.c (revision d02add54ea9b81a78bc70ea91f9561b49a3c9157)
1f53d15feSStephan Uphoff /*-
2f53d15feSStephan Uphoff  * Copyright (c) 2007 Stephan Uphoff <ups@FreeBSD.org>
3f53d15feSStephan Uphoff  * All rights reserved.
4f53d15feSStephan Uphoff  *
5f53d15feSStephan Uphoff  * Redistribution and use in source and binary forms, with or without
6f53d15feSStephan Uphoff  * modification, are permitted provided that the following conditions
7f53d15feSStephan Uphoff  * are met:
8f53d15feSStephan Uphoff  * 1. Redistributions of source code must retain the above copyright
9f53d15feSStephan Uphoff  *    notice, this list of conditions and the following disclaimer.
10f53d15feSStephan Uphoff  * 2. Redistributions in binary form must reproduce the above copyright
11f53d15feSStephan Uphoff  *    notice, this list of conditions and the following disclaimer in the
12f53d15feSStephan Uphoff  *    documentation and/or other materials provided with the distribution.
13f53d15feSStephan Uphoff  * 3. Neither the name of the author nor the names of any co-contributors
14f53d15feSStephan Uphoff  *    may be used to endorse or promote products derived from this software
15f53d15feSStephan Uphoff  *    without specific prior written permission.
16f53d15feSStephan Uphoff  *
17f53d15feSStephan Uphoff  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18f53d15feSStephan Uphoff  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19f53d15feSStephan Uphoff  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20f53d15feSStephan Uphoff  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21f53d15feSStephan Uphoff  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22f53d15feSStephan Uphoff  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23f53d15feSStephan Uphoff  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24f53d15feSStephan Uphoff  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25f53d15feSStephan Uphoff  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26f53d15feSStephan Uphoff  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27f53d15feSStephan Uphoff  * SUCH DAMAGE.
28f53d15feSStephan Uphoff  */
29f53d15feSStephan Uphoff 
30f53d15feSStephan Uphoff /*
31f53d15feSStephan Uphoff  * Machine independent bits of reader/writer lock implementation.
32f53d15feSStephan Uphoff  */
33f53d15feSStephan Uphoff 
34f53d15feSStephan Uphoff #include <sys/cdefs.h>
35f53d15feSStephan Uphoff __FBSDID("$FreeBSD$");
36f53d15feSStephan Uphoff 
37f53d15feSStephan Uphoff #include "opt_ddb.h"
38f53d15feSStephan Uphoff 
39f53d15feSStephan Uphoff #include <sys/param.h>
40f53d15feSStephan Uphoff #include <sys/systm.h>
41f53d15feSStephan Uphoff 
42f53d15feSStephan Uphoff #include <sys/kernel.h>
43f53d15feSStephan Uphoff #include <sys/ktr.h>
44f53d15feSStephan Uphoff #include <sys/lock.h>
45f53d15feSStephan Uphoff #include <sys/mutex.h>
46f53d15feSStephan Uphoff #include <sys/proc.h>
47f53d15feSStephan Uphoff #include <sys/rmlock.h>
48f53d15feSStephan Uphoff #include <sys/sched.h>
49f53d15feSStephan Uphoff #include <sys/smp.h>
50f53d15feSStephan Uphoff #include <sys/systm.h>
51f53d15feSStephan Uphoff #include <sys/turnstile.h>
52f53d15feSStephan Uphoff #include <sys/lock_profile.h>
53f53d15feSStephan Uphoff #include <machine/cpu.h>
54f53d15feSStephan Uphoff 
55f53d15feSStephan Uphoff #ifdef DDB
56f53d15feSStephan Uphoff #include <ddb/ddb.h>
57f53d15feSStephan Uphoff #endif
58f53d15feSStephan Uphoff 
59f53d15feSStephan Uphoff #define RMPF_ONQUEUE	1
60f53d15feSStephan Uphoff #define RMPF_SIGNAL	2
61f53d15feSStephan Uphoff 
62f53d15feSStephan Uphoff /*
63d02add54SRobert Watson  * To support usage of rmlock in CVs and msleep yet another list for the
64d02add54SRobert Watson  * priority tracker would be needed.  Using this lock for cv and msleep also
65d02add54SRobert Watson  * does not seem very useful
66f53d15feSStephan Uphoff  */
67f53d15feSStephan Uphoff 
68f53d15feSStephan Uphoff static __inline void compiler_memory_barrier(void) {
69f53d15feSStephan Uphoff 	__asm __volatile("":::"memory");
70f53d15feSStephan Uphoff }
71f53d15feSStephan Uphoff 
72f9721b43SAttilio Rao static void	assert_rm(struct lock_object *lock, int what);
73f53d15feSStephan Uphoff static void	lock_rm(struct lock_object *lock, int how);
74f53d15feSStephan Uphoff static int	unlock_rm(struct lock_object *lock);
75f53d15feSStephan Uphoff 
76f53d15feSStephan Uphoff struct lock_class lock_class_rm = {
77f53d15feSStephan Uphoff 	.lc_name = "rm",
78f53d15feSStephan Uphoff 	.lc_flags = LC_SLEEPLOCK | LC_RECURSABLE,
79f9721b43SAttilio Rao 	.lc_assert = assert_rm,
80f53d15feSStephan Uphoff #if 0
81f53d15feSStephan Uphoff #ifdef DDB
82f53d15feSStephan Uphoff 	.lc_ddb_show = db_show_rwlock,
83f53d15feSStephan Uphoff #endif
84f53d15feSStephan Uphoff #endif
85f53d15feSStephan Uphoff 	.lc_lock = lock_rm,
86f53d15feSStephan Uphoff 	.lc_unlock = unlock_rm,
87f53d15feSStephan Uphoff };
88f53d15feSStephan Uphoff 
89f53d15feSStephan Uphoff static void
90f9721b43SAttilio Rao assert_rm(struct lock_object *lock, int what)
91f9721b43SAttilio Rao {
92f9721b43SAttilio Rao 
93f9721b43SAttilio Rao 	panic("assert_rm called");
94f9721b43SAttilio Rao }
95f9721b43SAttilio Rao 
96f9721b43SAttilio Rao static void
97d02add54SRobert Watson lock_rm(struct lock_object *lock, int how)
98d02add54SRobert Watson {
99d02add54SRobert Watson 
100f53d15feSStephan Uphoff 	panic("lock_rm called");
101f53d15feSStephan Uphoff }
102f53d15feSStephan Uphoff 
103f53d15feSStephan Uphoff static int
104d02add54SRobert Watson unlock_rm(struct lock_object *lock)
105d02add54SRobert Watson {
106d02add54SRobert Watson 
107f53d15feSStephan Uphoff 	panic("unlock_rm called");
108f53d15feSStephan Uphoff }
109f53d15feSStephan Uphoff 
110f53d15feSStephan Uphoff static struct mtx rm_spinlock;
111f53d15feSStephan Uphoff 
112f53d15feSStephan Uphoff MTX_SYSINIT(rm_spinlock, &rm_spinlock, "rm_spinlock", MTX_SPIN);
113f53d15feSStephan Uphoff 
114f53d15feSStephan Uphoff /*
115f53d15feSStephan Uphoff  * Add or remove tracker from per cpu list.
116d02add54SRobert Watson  *
117d02add54SRobert Watson  * The per cpu list can be traversed at any time in forward direction from an
118d02add54SRobert Watson  * interrupt on the *local* cpu.
119f53d15feSStephan Uphoff  */
120f53d15feSStephan Uphoff static void inline
121d02add54SRobert Watson rm_tracker_add(struct pcpu *pc, struct rm_priotracker *tracker)
122d02add54SRobert Watson {
123f53d15feSStephan Uphoff 	struct rm_queue *next;
124d02add54SRobert Watson 
125f53d15feSStephan Uphoff 	/* Initialize all tracker pointers */
126f53d15feSStephan Uphoff 	tracker->rmp_cpuQueue.rmq_prev = &pc->pc_rm_queue;
127f53d15feSStephan Uphoff 	next = pc->pc_rm_queue.rmq_next;
128f53d15feSStephan Uphoff 	tracker->rmp_cpuQueue.rmq_next = next;
129d02add54SRobert Watson 
130d02add54SRobert Watson 	/* rmq_prev is not used during froward traversal. */
131f53d15feSStephan Uphoff 	next->rmq_prev = &tracker->rmp_cpuQueue;
132d02add54SRobert Watson 
133d02add54SRobert Watson 	/* Update pointer to first element. */
134f53d15feSStephan Uphoff 	pc->pc_rm_queue.rmq_next =  &tracker->rmp_cpuQueue;
135f53d15feSStephan Uphoff }
136f53d15feSStephan Uphoff 
137f53d15feSStephan Uphoff static void inline
138d02add54SRobert Watson rm_tracker_remove(struct pcpu *pc, struct rm_priotracker *tracker)
139d02add54SRobert Watson {
140f53d15feSStephan Uphoff 	struct rm_queue *next, *prev;
141d02add54SRobert Watson 
142f53d15feSStephan Uphoff 	next = tracker->rmp_cpuQueue.rmq_next;
143f53d15feSStephan Uphoff 	prev = tracker->rmp_cpuQueue.rmq_prev;
144d02add54SRobert Watson 
145d02add54SRobert Watson 	/* Not used during forward traversal. */
146f53d15feSStephan Uphoff 	next->rmq_prev = prev;
147d02add54SRobert Watson 
148d02add54SRobert Watson 	/* Remove from list. */
149f53d15feSStephan Uphoff 	prev->rmq_next = next;
150f53d15feSStephan Uphoff }
151f53d15feSStephan Uphoff 
152d02add54SRobert Watson static void
153d02add54SRobert Watson rm_cleanIPI(void *arg)
154d02add54SRobert Watson {
155f53d15feSStephan Uphoff 	struct pcpu *pc;
156f53d15feSStephan Uphoff 	struct rmlock *rm = arg;
157f53d15feSStephan Uphoff 	struct rm_priotracker *tracker;
158f53d15feSStephan Uphoff 	struct rm_queue *queue;
159f53d15feSStephan Uphoff 	pc = pcpu_find(curcpu);
160f53d15feSStephan Uphoff 
161d02add54SRobert Watson 	for (queue = pc->pc_rm_queue.rmq_next; queue != &pc->pc_rm_queue;
162f53d15feSStephan Uphoff 	    queue = queue->rmq_next) {
163f53d15feSStephan Uphoff 		tracker = (struct rm_priotracker *)queue;
164f53d15feSStephan Uphoff 		if (tracker->rmp_rmlock == rm && tracker->rmp_flags == 0) {
165f53d15feSStephan Uphoff 			tracker->rmp_flags = RMPF_ONQUEUE;
166f53d15feSStephan Uphoff 			mtx_lock_spin(&rm_spinlock);
167f53d15feSStephan Uphoff 			LIST_INSERT_HEAD(&rm->rm_activeReaders, tracker,
168f53d15feSStephan Uphoff 			    rmp_qentry);
169f53d15feSStephan Uphoff 			mtx_unlock_spin(&rm_spinlock);
170f53d15feSStephan Uphoff 		}
171f53d15feSStephan Uphoff 	}
172f53d15feSStephan Uphoff }
173f53d15feSStephan Uphoff 
174f53d15feSStephan Uphoff void
175f53d15feSStephan Uphoff rm_init(struct rmlock *rm, const char *name, int opts)
176f53d15feSStephan Uphoff {
177d02add54SRobert Watson 
178f53d15feSStephan Uphoff 	rm->rm_noreadtoken = 1;
179f53d15feSStephan Uphoff 	LIST_INIT(&rm->rm_activeReaders);
180f53d15feSStephan Uphoff 	mtx_init(&rm->rm_lock, name, "RM_MTX",MTX_NOWITNESS);
181d02add54SRobert Watson 	lock_init(&rm->lock_object, &lock_class_rm, name, NULL,
182d02add54SRobert Watson 	    (opts & LO_RECURSABLE)| LO_WITNESS);
183f53d15feSStephan Uphoff }
184f53d15feSStephan Uphoff 
185f53d15feSStephan Uphoff void
186f53d15feSStephan Uphoff rm_destroy(struct rmlock *rm)
187f53d15feSStephan Uphoff {
188d02add54SRobert Watson 
189f53d15feSStephan Uphoff 	mtx_destroy(&rm->rm_lock);
190f53d15feSStephan Uphoff 	lock_destroy(&rm->lock_object);
191f53d15feSStephan Uphoff }
192f53d15feSStephan Uphoff 
193433ea89aSRobert Watson int
194433ea89aSRobert Watson rm_wowned(struct rmlock *rm)
195433ea89aSRobert Watson {
196433ea89aSRobert Watson 
197433ea89aSRobert Watson 	return (mtx_owned(&rm->rm_lock));
198433ea89aSRobert Watson }
199433ea89aSRobert Watson 
200f53d15feSStephan Uphoff void
201f53d15feSStephan Uphoff rm_sysinit(void *arg)
202f53d15feSStephan Uphoff {
203d02add54SRobert Watson 
204f53d15feSStephan Uphoff 	struct rm_args *args = arg;
205f53d15feSStephan Uphoff 	rm_init(args->ra_rm, args->ra_desc, args->ra_opts);
206f53d15feSStephan Uphoff }
207f53d15feSStephan Uphoff 
208f53d15feSStephan Uphoff static void
209f53d15feSStephan Uphoff _rm_rlock_hard(struct rmlock *rm, struct rm_priotracker *tracker)
210f53d15feSStephan Uphoff {
211f53d15feSStephan Uphoff 	struct pcpu *pc;
212f53d15feSStephan Uphoff 	struct rm_queue *queue;
213f53d15feSStephan Uphoff 	struct rm_priotracker *atracker;
214f53d15feSStephan Uphoff 
215f53d15feSStephan Uphoff 	critical_enter();
216f53d15feSStephan Uphoff 	pc = pcpu_find(curcpu);
217f53d15feSStephan Uphoff 
218d02add54SRobert Watson 	/* Check if we just need to do a proper critical_exit. */
219f53d15feSStephan Uphoff 	if (0 == rm->rm_noreadtoken) {
220f53d15feSStephan Uphoff 		critical_exit();
221f53d15feSStephan Uphoff 		return;
222f53d15feSStephan Uphoff 	}
223f53d15feSStephan Uphoff 
224d02add54SRobert Watson 	/* Remove our tracker from the per cpu list. */
225f53d15feSStephan Uphoff 	rm_tracker_remove(pc, tracker);
226f53d15feSStephan Uphoff 
227d02add54SRobert Watson 	/* Check to see if the IPI granted us the lock after all. */
228f53d15feSStephan Uphoff 	if (tracker->rmp_flags) {
229d02add54SRobert Watson 		/* Just add back tracker - we hold the lock. */
230f53d15feSStephan Uphoff 		rm_tracker_add(pc, tracker);
231f53d15feSStephan Uphoff 		critical_exit();
232f53d15feSStephan Uphoff 		return;
233f53d15feSStephan Uphoff 	}
234f53d15feSStephan Uphoff 
235f53d15feSStephan Uphoff 	/*
236d02add54SRobert Watson 	 * We allow readers to aquire a lock even if a writer is blocked if
237d02add54SRobert Watson 	 * the lock is recursive and the reader already holds the lock.
238f53d15feSStephan Uphoff 	 */
239f53d15feSStephan Uphoff 	if ((rm->lock_object.lo_flags & LO_RECURSABLE) != 0) {
240f53d15feSStephan Uphoff 		/*
241f53d15feSStephan Uphoff 		 * Just grand the lock if this thread already have a tracker
242d02add54SRobert Watson 		 * for this lock on the per cpu queue.
243f53d15feSStephan Uphoff 		 */
244f53d15feSStephan Uphoff 		for (queue = pc->pc_rm_queue.rmq_next;
245d02add54SRobert Watson 		    queue !=  &pc->pc_rm_queue; queue = queue->rmq_next) {
246f53d15feSStephan Uphoff 			atracker = (struct rm_priotracker *)queue;
247f53d15feSStephan Uphoff 			if ((atracker->rmp_rmlock == rm) &&
248f53d15feSStephan Uphoff 			    (atracker->rmp_thread == tracker->rmp_thread)) {
249f53d15feSStephan Uphoff 				mtx_lock_spin(&rm_spinlock);
250d02add54SRobert Watson 				LIST_INSERT_HEAD(&rm->rm_activeReaders,
251d02add54SRobert Watson 				    tracker, rmp_qentry);
252f53d15feSStephan Uphoff 				tracker->rmp_flags = RMPF_ONQUEUE;
253f53d15feSStephan Uphoff 				mtx_unlock_spin(&rm_spinlock);
254f53d15feSStephan Uphoff 				rm_tracker_add(pc, tracker);
255f53d15feSStephan Uphoff 				critical_exit();
256f53d15feSStephan Uphoff 				return;
257f53d15feSStephan Uphoff 			}
258f53d15feSStephan Uphoff 		}
259f53d15feSStephan Uphoff 	}
260f53d15feSStephan Uphoff 
261f53d15feSStephan Uphoff 	sched_unpin();
262f53d15feSStephan Uphoff 	critical_exit();
263f53d15feSStephan Uphoff 
264f53d15feSStephan Uphoff 	mtx_lock(&rm->rm_lock);
265f53d15feSStephan Uphoff 	rm->rm_noreadtoken = 0;
266f53d15feSStephan Uphoff 	critical_enter();
267f53d15feSStephan Uphoff 
268f53d15feSStephan Uphoff 	pc = pcpu_find(curcpu);
269f53d15feSStephan Uphoff 	rm_tracker_add(pc, tracker);
270f53d15feSStephan Uphoff 	sched_pin();
271f53d15feSStephan Uphoff 	critical_exit();
272f53d15feSStephan Uphoff 
273f53d15feSStephan Uphoff 	mtx_unlock(&rm->rm_lock);
274f53d15feSStephan Uphoff }
275f53d15feSStephan Uphoff 
276f53d15feSStephan Uphoff void
277f53d15feSStephan Uphoff _rm_rlock(struct rmlock *rm, struct rm_priotracker *tracker)
278f53d15feSStephan Uphoff {
279f53d15feSStephan Uphoff 	struct thread *td = curthread;
280f53d15feSStephan Uphoff 	struct pcpu *pc;
281f53d15feSStephan Uphoff 
282f53d15feSStephan Uphoff 	tracker->rmp_flags  = 0;
283f53d15feSStephan Uphoff 	tracker->rmp_thread = td;
284f53d15feSStephan Uphoff 	tracker->rmp_rmlock = rm;
285f53d15feSStephan Uphoff 
286f53d15feSStephan Uphoff 	td->td_critnest++;	/* critical_enter(); */
287f53d15feSStephan Uphoff 
288f53d15feSStephan Uphoff 	compiler_memory_barrier();
289f53d15feSStephan Uphoff 
290f53d15feSStephan Uphoff 	pc = cpuid_to_pcpu[td->td_oncpu]; /* pcpu_find(td->td_oncpu); */
291f53d15feSStephan Uphoff 
292f53d15feSStephan Uphoff 	rm_tracker_add(pc, tracker);
293f53d15feSStephan Uphoff 
294f53d15feSStephan Uphoff 	td->td_pinned++; /*  sched_pin(); */
295f53d15feSStephan Uphoff 
296f53d15feSStephan Uphoff 	compiler_memory_barrier();
297f53d15feSStephan Uphoff 
298f53d15feSStephan Uphoff 	td->td_critnest--;
299f53d15feSStephan Uphoff 
300f53d15feSStephan Uphoff 	/*
301d02add54SRobert Watson 	 * Fast path to combine two common conditions into a single
302d02add54SRobert Watson 	 * conditional jump.
303f53d15feSStephan Uphoff 	 */
304d02add54SRobert Watson 	if (0 == (td->td_owepreempt |  rm->rm_noreadtoken))
305f53d15feSStephan Uphoff 		return;
306f53d15feSStephan Uphoff 
307d02add54SRobert Watson 	/* We do not have a read token and need to acquire one. */
308f53d15feSStephan Uphoff 	_rm_rlock_hard(rm, tracker);
309f53d15feSStephan Uphoff }
310f53d15feSStephan Uphoff 
311f53d15feSStephan Uphoff static void
312f53d15feSStephan Uphoff _rm_unlock_hard(struct thread *td,struct rm_priotracker *tracker)
313f53d15feSStephan Uphoff {
314f53d15feSStephan Uphoff 
315f53d15feSStephan Uphoff 	if (td->td_owepreempt) {
316f53d15feSStephan Uphoff 		td->td_critnest++;
317f53d15feSStephan Uphoff 		critical_exit();
318f53d15feSStephan Uphoff 	}
319f53d15feSStephan Uphoff 
320d02add54SRobert Watson 	if (!tracker->rmp_flags)
321f53d15feSStephan Uphoff 		return;
322f53d15feSStephan Uphoff 
323f53d15feSStephan Uphoff 	mtx_lock_spin(&rm_spinlock);
324f53d15feSStephan Uphoff 	LIST_REMOVE(tracker, rmp_qentry);
325f53d15feSStephan Uphoff 
326f53d15feSStephan Uphoff 	if (tracker->rmp_flags & RMPF_SIGNAL) {
327f53d15feSStephan Uphoff 		struct rmlock *rm;
328f53d15feSStephan Uphoff 		struct turnstile *ts;
329f53d15feSStephan Uphoff 
330f53d15feSStephan Uphoff 		rm = tracker->rmp_rmlock;
331f53d15feSStephan Uphoff 
332f53d15feSStephan Uphoff 		turnstile_chain_lock(&rm->lock_object);
333f53d15feSStephan Uphoff 		mtx_unlock_spin(&rm_spinlock);
334f53d15feSStephan Uphoff 
335f53d15feSStephan Uphoff 		ts = turnstile_lookup(&rm->lock_object);
336f53d15feSStephan Uphoff 
337f53d15feSStephan Uphoff 		turnstile_signal(ts, TS_EXCLUSIVE_QUEUE);
338f53d15feSStephan Uphoff 		turnstile_unpend(ts, TS_EXCLUSIVE_LOCK);
339f53d15feSStephan Uphoff 		turnstile_chain_unlock(&rm->lock_object);
340f53d15feSStephan Uphoff 	} else
341f53d15feSStephan Uphoff 		mtx_unlock_spin(&rm_spinlock);
342f53d15feSStephan Uphoff }
343f53d15feSStephan Uphoff 
344f53d15feSStephan Uphoff void
345f53d15feSStephan Uphoff _rm_runlock(struct rmlock *rm, struct rm_priotracker *tracker)
346f53d15feSStephan Uphoff {
347f53d15feSStephan Uphoff 	struct pcpu *pc;
348f53d15feSStephan Uphoff 	struct thread *td = tracker->rmp_thread;
349f53d15feSStephan Uphoff 
350f53d15feSStephan Uphoff 	td->td_critnest++;	/* critical_enter(); */
351f53d15feSStephan Uphoff 	pc = cpuid_to_pcpu[td->td_oncpu]; /* pcpu_find(td->td_oncpu); */
352f53d15feSStephan Uphoff 	rm_tracker_remove(pc, tracker);
353f53d15feSStephan Uphoff 	td->td_critnest--;
354f53d15feSStephan Uphoff 	td->td_pinned--; /*  sched_unpin(); */
355f53d15feSStephan Uphoff 
356f53d15feSStephan Uphoff 	if (0 == (td->td_owepreempt | tracker->rmp_flags))
357f53d15feSStephan Uphoff 		return;
358f53d15feSStephan Uphoff 
359f53d15feSStephan Uphoff 	_rm_unlock_hard(td, tracker);
360f53d15feSStephan Uphoff }
361f53d15feSStephan Uphoff 
362f53d15feSStephan Uphoff void
363f53d15feSStephan Uphoff _rm_wlock(struct rmlock *rm)
364f53d15feSStephan Uphoff {
365f53d15feSStephan Uphoff 	struct rm_priotracker *prio;
366f53d15feSStephan Uphoff 	struct turnstile *ts;
367f53d15feSStephan Uphoff 
368f53d15feSStephan Uphoff 	mtx_lock(&rm->rm_lock);
369f53d15feSStephan Uphoff 
370f53d15feSStephan Uphoff 	if (rm->rm_noreadtoken == 0) {
371f53d15feSStephan Uphoff 		/* Get all read tokens back */
372f53d15feSStephan Uphoff 
373f53d15feSStephan Uphoff 		rm->rm_noreadtoken = 1;
374f53d15feSStephan Uphoff 
375f53d15feSStephan Uphoff 		/*
376d02add54SRobert Watson 		 * Assumes rm->rm_noreadtoken update is visible on other CPUs
377d02add54SRobert Watson 		 * before rm_cleanIPI is called.
378f53d15feSStephan Uphoff 		 */
379f53d15feSStephan Uphoff #ifdef SMP
380f53d15feSStephan Uphoff    		smp_rendezvous(smp_no_rendevous_barrier,
381f53d15feSStephan Uphoff 		    rm_cleanIPI,
382d02add54SRobert Watson 		    smp_no_rendevous_barrier,
383d02add54SRobert Watson 		    rm);
384f53d15feSStephan Uphoff 
385f53d15feSStephan Uphoff #else
386f53d15feSStephan Uphoff 		rm_cleanIPI(rm);
387f53d15feSStephan Uphoff #endif
388f53d15feSStephan Uphoff 
389f53d15feSStephan Uphoff 		mtx_lock_spin(&rm_spinlock);
390f53d15feSStephan Uphoff 		while ((prio = LIST_FIRST(&rm->rm_activeReaders)) != NULL) {
391f53d15feSStephan Uphoff 			ts = turnstile_trywait(&rm->lock_object);
392f53d15feSStephan Uphoff 			prio->rmp_flags = RMPF_ONQUEUE | RMPF_SIGNAL;
393f53d15feSStephan Uphoff 			mtx_unlock_spin(&rm_spinlock);
394f53d15feSStephan Uphoff 			turnstile_wait(ts, prio->rmp_thread,
395f53d15feSStephan Uphoff 			    TS_EXCLUSIVE_QUEUE);
396f53d15feSStephan Uphoff 			mtx_lock_spin(&rm_spinlock);
397f53d15feSStephan Uphoff 		}
398f53d15feSStephan Uphoff 		mtx_unlock_spin(&rm_spinlock);
399f53d15feSStephan Uphoff 	}
400f53d15feSStephan Uphoff }
401f53d15feSStephan Uphoff 
402f53d15feSStephan Uphoff void
403f53d15feSStephan Uphoff _rm_wunlock(struct rmlock *rm)
404f53d15feSStephan Uphoff {
405d02add54SRobert Watson 
406f53d15feSStephan Uphoff 	mtx_unlock(&rm->rm_lock);
407f53d15feSStephan Uphoff }
408f53d15feSStephan Uphoff 
409f53d15feSStephan Uphoff #ifdef LOCK_DEBUG
410f53d15feSStephan Uphoff 
411f53d15feSStephan Uphoff void _rm_wlock_debug(struct rmlock *rm, const char *file, int line)
412f53d15feSStephan Uphoff {
413f53d15feSStephan Uphoff 
414f53d15feSStephan Uphoff 	WITNESS_CHECKORDER(&rm->lock_object, LOP_NEWORDER | LOP_EXCLUSIVE,
41541313430SJohn Baldwin 	    file, line, NULL);
416f53d15feSStephan Uphoff 
417f53d15feSStephan Uphoff 	_rm_wlock(rm);
418f53d15feSStephan Uphoff 
419f53d15feSStephan Uphoff 	LOCK_LOG_LOCK("RMWLOCK", &rm->lock_object, 0, 0, file, line);
420f53d15feSStephan Uphoff 
421f53d15feSStephan Uphoff 	WITNESS_LOCK(&rm->lock_object, LOP_EXCLUSIVE, file, line);
422f53d15feSStephan Uphoff 
423f53d15feSStephan Uphoff 	curthread->td_locks++;
424f53d15feSStephan Uphoff 
425f53d15feSStephan Uphoff }
426f53d15feSStephan Uphoff 
427d02add54SRobert Watson void
428d02add54SRobert Watson _rm_wunlock_debug(struct rmlock *rm, const char *file, int line)
429f53d15feSStephan Uphoff {
430d02add54SRobert Watson 
431f53d15feSStephan Uphoff 	curthread->td_locks--;
432f53d15feSStephan Uphoff 	WITNESS_UNLOCK(&rm->lock_object, LOP_EXCLUSIVE, file, line);
433f53d15feSStephan Uphoff 	LOCK_LOG_LOCK("RMWUNLOCK", &rm->lock_object, 0, 0, file, line);
434f53d15feSStephan Uphoff 	_rm_wunlock(rm);
435f53d15feSStephan Uphoff }
436f53d15feSStephan Uphoff 
437f53d15feSStephan Uphoff void
438f53d15feSStephan Uphoff _rm_rlock_debug(struct rmlock *rm, struct rm_priotracker *tracker,
439f53d15feSStephan Uphoff     const char *file, int line)
440f53d15feSStephan Uphoff {
441f53d15feSStephan Uphoff 
44241313430SJohn Baldwin 	WITNESS_CHECKORDER(&rm->lock_object, LOP_NEWORDER, file, line, NULL);
443f53d15feSStephan Uphoff 
444f53d15feSStephan Uphoff 	_rm_rlock(rm, tracker);
445f53d15feSStephan Uphoff 
446f53d15feSStephan Uphoff 	LOCK_LOG_LOCK("RMRLOCK", &rm->lock_object, 0, 0, file, line);
447f53d15feSStephan Uphoff 
448f53d15feSStephan Uphoff 	WITNESS_LOCK(&rm->lock_object, 0, file, line);
449f53d15feSStephan Uphoff 
450f53d15feSStephan Uphoff 	curthread->td_locks++;
451f53d15feSStephan Uphoff }
452f53d15feSStephan Uphoff 
453f53d15feSStephan Uphoff void
454f53d15feSStephan Uphoff _rm_runlock_debug(struct rmlock *rm,  struct rm_priotracker *tracker,
455d02add54SRobert Watson     const char *file, int line)
456d02add54SRobert Watson {
457d02add54SRobert Watson 
458f53d15feSStephan Uphoff 	curthread->td_locks--;
459f53d15feSStephan Uphoff 	WITNESS_UNLOCK(&rm->lock_object, 0, file, line);
460f53d15feSStephan Uphoff 	LOCK_LOG_LOCK("RMRUNLOCK", &rm->lock_object, 0, 0, file, line);
461f53d15feSStephan Uphoff 	_rm_runlock(rm, tracker);
462f53d15feSStephan Uphoff }
463f53d15feSStephan Uphoff 
464f53d15feSStephan Uphoff #else
465d02add54SRobert Watson 
466f53d15feSStephan Uphoff /*
467d02add54SRobert Watson  * Just strip out file and line arguments if no lock debugging is enabled in
468d02add54SRobert Watson  * the kernel - we are called from a kernel module.
469f53d15feSStephan Uphoff  */
470d02add54SRobert Watson void
471d02add54SRobert Watson _rm_wlock_debug(struct rmlock *rm, const char *file, int line)
472f53d15feSStephan Uphoff {
473d02add54SRobert Watson 
474f53d15feSStephan Uphoff 	_rm_wlock(rm);
475f53d15feSStephan Uphoff }
476f53d15feSStephan Uphoff 
477d02add54SRobert Watson void
478d02add54SRobert Watson _rm_wunlock_debug(struct rmlock *rm, const char *file, int line)
479f53d15feSStephan Uphoff {
480d02add54SRobert Watson 
481f53d15feSStephan Uphoff 	_rm_wunlock(rm);
482f53d15feSStephan Uphoff }
483f53d15feSStephan Uphoff 
484f53d15feSStephan Uphoff void
485f53d15feSStephan Uphoff _rm_rlock_debug(struct rmlock *rm, struct rm_priotracker *tracker,
486f53d15feSStephan Uphoff     const char *file, int line)
487f53d15feSStephan Uphoff {
488d02add54SRobert Watson 
489f53d15feSStephan Uphoff 	_rm_rlock(rm, tracker);
490f53d15feSStephan Uphoff }
491f53d15feSStephan Uphoff 
492f53d15feSStephan Uphoff void
493f53d15feSStephan Uphoff _rm_runlock_debug(struct rmlock *rm,  struct rm_priotracker *tracker,
494f53d15feSStephan Uphoff     const char *file, int line) {
495d02add54SRobert Watson 
496f53d15feSStephan Uphoff 	_rm_runlock(rm, tracker);
497f53d15feSStephan Uphoff }
498f53d15feSStephan Uphoff 
499f53d15feSStephan Uphoff #endif
500