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" 38a5aedd68SStacey Son #include "opt_kdtrace.h" 39f53d15feSStephan Uphoff 40f53d15feSStephan Uphoff #include <sys/param.h> 41f53d15feSStephan Uphoff #include <sys/systm.h> 42f53d15feSStephan Uphoff 43f53d15feSStephan Uphoff #include <sys/kernel.h> 44f53d15feSStephan Uphoff #include <sys/ktr.h> 45f53d15feSStephan Uphoff #include <sys/lock.h> 46f53d15feSStephan Uphoff #include <sys/mutex.h> 47f53d15feSStephan Uphoff #include <sys/proc.h> 48f53d15feSStephan Uphoff #include <sys/rmlock.h> 49f53d15feSStephan Uphoff #include <sys/sched.h> 50f53d15feSStephan Uphoff #include <sys/smp.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); 74a5aedd68SStacey Son #ifdef KDTRACE_HOOKS 75a5aedd68SStacey Son static int owner_rm(struct lock_object *lock, struct thread **owner); 76a5aedd68SStacey Son #endif 77f53d15feSStephan Uphoff static int unlock_rm(struct lock_object *lock); 78f53d15feSStephan Uphoff 79f53d15feSStephan Uphoff struct lock_class lock_class_rm = { 80f53d15feSStephan Uphoff .lc_name = "rm", 81f53d15feSStephan Uphoff .lc_flags = LC_SLEEPLOCK | LC_RECURSABLE, 82f9721b43SAttilio Rao .lc_assert = assert_rm, 83f53d15feSStephan Uphoff #if 0 84f53d15feSStephan Uphoff #ifdef DDB 85f53d15feSStephan Uphoff .lc_ddb_show = db_show_rwlock, 86f53d15feSStephan Uphoff #endif 87f53d15feSStephan Uphoff #endif 88f53d15feSStephan Uphoff .lc_lock = lock_rm, 89f53d15feSStephan Uphoff .lc_unlock = unlock_rm, 90a5aedd68SStacey Son #ifdef KDTRACE_HOOKS 91a5aedd68SStacey Son .lc_owner = owner_rm, 92a5aedd68SStacey Son #endif 93f53d15feSStephan Uphoff }; 94f53d15feSStephan Uphoff 95f53d15feSStephan Uphoff static void 96f9721b43SAttilio Rao assert_rm(struct lock_object *lock, int what) 97f9721b43SAttilio Rao { 98f9721b43SAttilio Rao 99f9721b43SAttilio Rao panic("assert_rm called"); 100f9721b43SAttilio Rao } 101f9721b43SAttilio Rao 102f9721b43SAttilio Rao static void 103d02add54SRobert Watson lock_rm(struct lock_object *lock, int how) 104d02add54SRobert Watson { 105d02add54SRobert Watson 106f53d15feSStephan Uphoff panic("lock_rm called"); 107f53d15feSStephan Uphoff } 108f53d15feSStephan Uphoff 109f53d15feSStephan Uphoff static int 110d02add54SRobert Watson unlock_rm(struct lock_object *lock) 111d02add54SRobert Watson { 112d02add54SRobert Watson 113f53d15feSStephan Uphoff panic("unlock_rm called"); 114f53d15feSStephan Uphoff } 115f53d15feSStephan Uphoff 116a5aedd68SStacey Son #ifdef KDTRACE_HOOKS 117a5aedd68SStacey Son static int 118a5aedd68SStacey Son owner_rm(struct lock_object *lock, struct thread **owner) 119a5aedd68SStacey Son { 120a5aedd68SStacey Son 121a5aedd68SStacey Son panic("owner_rm called"); 122a5aedd68SStacey Son } 123a5aedd68SStacey Son #endif 124a5aedd68SStacey Son 125f53d15feSStephan Uphoff static struct mtx rm_spinlock; 126f53d15feSStephan Uphoff 127f53d15feSStephan Uphoff MTX_SYSINIT(rm_spinlock, &rm_spinlock, "rm_spinlock", MTX_SPIN); 128f53d15feSStephan Uphoff 129f53d15feSStephan Uphoff /* 130c7ca33d1SRobert Watson * Add or remove tracker from per-cpu list. 131d02add54SRobert Watson * 132c7ca33d1SRobert Watson * The per-cpu list can be traversed at any time in forward direction from an 133d02add54SRobert Watson * interrupt on the *local* cpu. 134f53d15feSStephan Uphoff */ 135f53d15feSStephan Uphoff static void inline 136d02add54SRobert Watson rm_tracker_add(struct pcpu *pc, struct rm_priotracker *tracker) 137d02add54SRobert Watson { 138f53d15feSStephan Uphoff struct rm_queue *next; 139d02add54SRobert Watson 140f53d15feSStephan Uphoff /* Initialize all tracker pointers */ 141f53d15feSStephan Uphoff tracker->rmp_cpuQueue.rmq_prev = &pc->pc_rm_queue; 142f53d15feSStephan Uphoff next = pc->pc_rm_queue.rmq_next; 143f53d15feSStephan Uphoff tracker->rmp_cpuQueue.rmq_next = next; 144d02add54SRobert Watson 145d02add54SRobert Watson /* rmq_prev is not used during froward traversal. */ 146f53d15feSStephan Uphoff next->rmq_prev = &tracker->rmp_cpuQueue; 147d02add54SRobert Watson 148d02add54SRobert Watson /* Update pointer to first element. */ 149f53d15feSStephan Uphoff pc->pc_rm_queue.rmq_next = &tracker->rmp_cpuQueue; 150f53d15feSStephan Uphoff } 151f53d15feSStephan Uphoff 152f53d15feSStephan Uphoff static void inline 153d02add54SRobert Watson rm_tracker_remove(struct pcpu *pc, struct rm_priotracker *tracker) 154d02add54SRobert Watson { 155f53d15feSStephan Uphoff struct rm_queue *next, *prev; 156d02add54SRobert Watson 157f53d15feSStephan Uphoff next = tracker->rmp_cpuQueue.rmq_next; 158f53d15feSStephan Uphoff prev = tracker->rmp_cpuQueue.rmq_prev; 159d02add54SRobert Watson 160d02add54SRobert Watson /* Not used during forward traversal. */ 161f53d15feSStephan Uphoff next->rmq_prev = prev; 162d02add54SRobert Watson 163d02add54SRobert Watson /* Remove from list. */ 164f53d15feSStephan Uphoff prev->rmq_next = next; 165f53d15feSStephan Uphoff } 166f53d15feSStephan Uphoff 167d02add54SRobert Watson static void 168d02add54SRobert Watson rm_cleanIPI(void *arg) 169d02add54SRobert Watson { 170f53d15feSStephan Uphoff struct pcpu *pc; 171f53d15feSStephan Uphoff struct rmlock *rm = arg; 172f53d15feSStephan Uphoff struct rm_priotracker *tracker; 173f53d15feSStephan Uphoff struct rm_queue *queue; 174f53d15feSStephan Uphoff pc = pcpu_find(curcpu); 175f53d15feSStephan Uphoff 176d02add54SRobert Watson for (queue = pc->pc_rm_queue.rmq_next; queue != &pc->pc_rm_queue; 177f53d15feSStephan Uphoff queue = queue->rmq_next) { 178f53d15feSStephan Uphoff tracker = (struct rm_priotracker *)queue; 179f53d15feSStephan Uphoff if (tracker->rmp_rmlock == rm && tracker->rmp_flags == 0) { 180f53d15feSStephan Uphoff tracker->rmp_flags = RMPF_ONQUEUE; 181f53d15feSStephan Uphoff mtx_lock_spin(&rm_spinlock); 182f53d15feSStephan Uphoff LIST_INSERT_HEAD(&rm->rm_activeReaders, tracker, 183f53d15feSStephan Uphoff rmp_qentry); 184f53d15feSStephan Uphoff mtx_unlock_spin(&rm_spinlock); 185f53d15feSStephan Uphoff } 186f53d15feSStephan Uphoff } 187f53d15feSStephan Uphoff } 188f53d15feSStephan Uphoff 18936058c09SMax Laier CTASSERT((RM_SLEEPABLE & LO_CLASSFLAGS) == RM_SLEEPABLE); 19036058c09SMax Laier 191f53d15feSStephan Uphoff void 1921a109c1cSRobert Watson rm_init_flags(struct rmlock *rm, const char *name, int opts) 193f53d15feSStephan Uphoff { 1941a109c1cSRobert Watson int liflags; 195d02add54SRobert Watson 1961a109c1cSRobert Watson liflags = 0; 1971a109c1cSRobert Watson if (!(opts & RM_NOWITNESS)) 1981a109c1cSRobert Watson liflags |= LO_WITNESS; 1991a109c1cSRobert Watson if (opts & RM_RECURSE) 2001a109c1cSRobert Watson liflags |= LO_RECURSABLE; 20136058c09SMax Laier rm->rm_writecpus = all_cpus; 202f53d15feSStephan Uphoff LIST_INIT(&rm->rm_activeReaders); 20336058c09SMax Laier if (opts & RM_SLEEPABLE) { 20436058c09SMax Laier liflags |= RM_SLEEPABLE; 20536058c09SMax Laier sx_init_flags(&rm->rm_lock_sx, "rmlock_sx", SX_RECURSE); 20636058c09SMax Laier } else 20736058c09SMax Laier mtx_init(&rm->rm_lock_mtx, name, "rmlock_mtx", MTX_NOWITNESS); 2081a109c1cSRobert Watson lock_init(&rm->lock_object, &lock_class_rm, name, NULL, liflags); 2091a109c1cSRobert Watson } 2101a109c1cSRobert Watson 2111a109c1cSRobert Watson void 2121a109c1cSRobert Watson rm_init(struct rmlock *rm, const char *name) 2131a109c1cSRobert Watson { 2141a109c1cSRobert Watson 2151a109c1cSRobert Watson rm_init_flags(rm, name, 0); 216f53d15feSStephan Uphoff } 217f53d15feSStephan Uphoff 218f53d15feSStephan Uphoff void 219f53d15feSStephan Uphoff rm_destroy(struct rmlock *rm) 220f53d15feSStephan Uphoff { 221d02add54SRobert Watson 22236058c09SMax Laier if (rm->lock_object.lo_flags & RM_SLEEPABLE) 22336058c09SMax Laier sx_destroy(&rm->rm_lock_sx); 22436058c09SMax Laier else 22536058c09SMax Laier mtx_destroy(&rm->rm_lock_mtx); 226f53d15feSStephan Uphoff lock_destroy(&rm->lock_object); 227f53d15feSStephan Uphoff } 228f53d15feSStephan Uphoff 229433ea89aSRobert Watson int 230433ea89aSRobert Watson rm_wowned(struct rmlock *rm) 231433ea89aSRobert Watson { 232433ea89aSRobert Watson 23336058c09SMax Laier if (rm->lock_object.lo_flags & RM_SLEEPABLE) 23436058c09SMax Laier return (sx_xlocked(&rm->rm_lock_sx)); 23536058c09SMax Laier else 23636058c09SMax Laier return (mtx_owned(&rm->rm_lock_mtx)); 237433ea89aSRobert Watson } 238433ea89aSRobert Watson 239f53d15feSStephan Uphoff void 240f53d15feSStephan Uphoff rm_sysinit(void *arg) 241f53d15feSStephan Uphoff { 242f53d15feSStephan Uphoff struct rm_args *args = arg; 2431a109c1cSRobert Watson 2441a109c1cSRobert Watson rm_init(args->ra_rm, args->ra_desc); 2451a109c1cSRobert Watson } 2461a109c1cSRobert Watson 2471a109c1cSRobert Watson void 2481a109c1cSRobert Watson rm_sysinit_flags(void *arg) 2491a109c1cSRobert Watson { 2501a109c1cSRobert Watson struct rm_args_flags *args = arg; 2511a109c1cSRobert Watson 2521a109c1cSRobert Watson rm_init_flags(args->ra_rm, args->ra_desc, args->ra_opts); 253f53d15feSStephan Uphoff } 254f53d15feSStephan Uphoff 25536058c09SMax Laier static int 25636058c09SMax Laier _rm_rlock_hard(struct rmlock *rm, struct rm_priotracker *tracker, int trylock) 257f53d15feSStephan Uphoff { 258f53d15feSStephan Uphoff struct pcpu *pc; 259f53d15feSStephan Uphoff struct rm_queue *queue; 260f53d15feSStephan Uphoff struct rm_priotracker *atracker; 261f53d15feSStephan Uphoff 262f53d15feSStephan Uphoff critical_enter(); 263f53d15feSStephan Uphoff pc = pcpu_find(curcpu); 264f53d15feSStephan Uphoff 265d02add54SRobert Watson /* Check if we just need to do a proper critical_exit. */ 266*71a19bdcSAttilio Rao if (!CPU_OVERLAP(&pc->pc_cpumask, &rm->rm_writecpus)) { 267f53d15feSStephan Uphoff critical_exit(); 26836058c09SMax Laier return (1); 269f53d15feSStephan Uphoff } 270f53d15feSStephan Uphoff 271c7ca33d1SRobert Watson /* Remove our tracker from the per-cpu list. */ 272f53d15feSStephan Uphoff rm_tracker_remove(pc, tracker); 273f53d15feSStephan Uphoff 274d02add54SRobert Watson /* Check to see if the IPI granted us the lock after all. */ 275f53d15feSStephan Uphoff if (tracker->rmp_flags) { 276d02add54SRobert Watson /* Just add back tracker - we hold the lock. */ 277f53d15feSStephan Uphoff rm_tracker_add(pc, tracker); 278f53d15feSStephan Uphoff critical_exit(); 27936058c09SMax Laier return (1); 280f53d15feSStephan Uphoff } 281f53d15feSStephan Uphoff 282f53d15feSStephan Uphoff /* 283d02add54SRobert Watson * We allow readers to aquire a lock even if a writer is blocked if 284d02add54SRobert Watson * the lock is recursive and the reader already holds the lock. 285f53d15feSStephan Uphoff */ 286f53d15feSStephan Uphoff if ((rm->lock_object.lo_flags & LO_RECURSABLE) != 0) { 287f53d15feSStephan Uphoff /* 288c7ca33d1SRobert Watson * Just grant the lock if this thread already has a tracker 289c7ca33d1SRobert Watson * for this lock on the per-cpu queue. 290f53d15feSStephan Uphoff */ 291f53d15feSStephan Uphoff for (queue = pc->pc_rm_queue.rmq_next; 292d02add54SRobert Watson queue != &pc->pc_rm_queue; queue = queue->rmq_next) { 293f53d15feSStephan Uphoff atracker = (struct rm_priotracker *)queue; 294f53d15feSStephan Uphoff if ((atracker->rmp_rmlock == rm) && 295f53d15feSStephan Uphoff (atracker->rmp_thread == tracker->rmp_thread)) { 296f53d15feSStephan Uphoff mtx_lock_spin(&rm_spinlock); 297d02add54SRobert Watson LIST_INSERT_HEAD(&rm->rm_activeReaders, 298d02add54SRobert Watson tracker, rmp_qentry); 299f53d15feSStephan Uphoff tracker->rmp_flags = RMPF_ONQUEUE; 300f53d15feSStephan Uphoff mtx_unlock_spin(&rm_spinlock); 301f53d15feSStephan Uphoff rm_tracker_add(pc, tracker); 302f53d15feSStephan Uphoff critical_exit(); 30336058c09SMax Laier return (1); 304f53d15feSStephan Uphoff } 305f53d15feSStephan Uphoff } 306f53d15feSStephan Uphoff } 307f53d15feSStephan Uphoff 308f53d15feSStephan Uphoff sched_unpin(); 309f53d15feSStephan Uphoff critical_exit(); 310f53d15feSStephan Uphoff 31136058c09SMax Laier if (trylock) { 31236058c09SMax Laier if (rm->lock_object.lo_flags & RM_SLEEPABLE) { 31336058c09SMax Laier if (!sx_try_xlock(&rm->rm_lock_sx)) 31436058c09SMax Laier return (0); 31536058c09SMax Laier } else { 31636058c09SMax Laier if (!mtx_trylock(&rm->rm_lock_mtx)) 31736058c09SMax Laier return (0); 31836058c09SMax Laier } 31936058c09SMax Laier } else { 32036058c09SMax Laier if (rm->lock_object.lo_flags & RM_SLEEPABLE) 32136058c09SMax Laier sx_xlock(&rm->rm_lock_sx); 32236058c09SMax Laier else 32336058c09SMax Laier mtx_lock(&rm->rm_lock_mtx); 32436058c09SMax Laier } 325f53d15feSStephan Uphoff 32636058c09SMax Laier critical_enter(); 327f53d15feSStephan Uphoff pc = pcpu_find(curcpu); 328*71a19bdcSAttilio Rao CPU_NAND(&rm->rm_writecpus, &pc->pc_cpumask); 329f53d15feSStephan Uphoff rm_tracker_add(pc, tracker); 330f53d15feSStephan Uphoff sched_pin(); 331f53d15feSStephan Uphoff critical_exit(); 332f53d15feSStephan Uphoff 33336058c09SMax Laier if (rm->lock_object.lo_flags & RM_SLEEPABLE) 33436058c09SMax Laier sx_xunlock(&rm->rm_lock_sx); 33536058c09SMax Laier else 33636058c09SMax Laier mtx_unlock(&rm->rm_lock_mtx); 33736058c09SMax Laier 33836058c09SMax Laier return (1); 339f53d15feSStephan Uphoff } 340f53d15feSStephan Uphoff 34136058c09SMax Laier int 34236058c09SMax Laier _rm_rlock(struct rmlock *rm, struct rm_priotracker *tracker, int trylock) 343f53d15feSStephan Uphoff { 344f53d15feSStephan Uphoff struct thread *td = curthread; 345f53d15feSStephan Uphoff struct pcpu *pc; 346f53d15feSStephan Uphoff 347f53d15feSStephan Uphoff tracker->rmp_flags = 0; 348f53d15feSStephan Uphoff tracker->rmp_thread = td; 349f53d15feSStephan Uphoff tracker->rmp_rmlock = rm; 350f53d15feSStephan Uphoff 351f53d15feSStephan Uphoff td->td_critnest++; /* critical_enter(); */ 352f53d15feSStephan Uphoff 353f53d15feSStephan Uphoff compiler_memory_barrier(); 354f53d15feSStephan Uphoff 355f53d15feSStephan Uphoff pc = cpuid_to_pcpu[td->td_oncpu]; /* pcpu_find(td->td_oncpu); */ 356f53d15feSStephan Uphoff 357f53d15feSStephan Uphoff rm_tracker_add(pc, tracker); 358f53d15feSStephan Uphoff 35982b7a39cSRobert Watson sched_pin(); 360f53d15feSStephan Uphoff 361f53d15feSStephan Uphoff compiler_memory_barrier(); 362f53d15feSStephan Uphoff 363f53d15feSStephan Uphoff td->td_critnest--; 364f53d15feSStephan Uphoff 365f53d15feSStephan Uphoff /* 366d02add54SRobert Watson * Fast path to combine two common conditions into a single 367d02add54SRobert Watson * conditional jump. 368f53d15feSStephan Uphoff */ 369*71a19bdcSAttilio Rao if (0 == (td->td_owepreempt | 370*71a19bdcSAttilio Rao CPU_OVERLAP(&rm->rm_writecpus, &pc->pc_cpumask))) 37136058c09SMax Laier return (1); 372f53d15feSStephan Uphoff 373d02add54SRobert Watson /* We do not have a read token and need to acquire one. */ 37436058c09SMax Laier return _rm_rlock_hard(rm, tracker, trylock); 375f53d15feSStephan Uphoff } 376f53d15feSStephan Uphoff 377f53d15feSStephan Uphoff static void 378f53d15feSStephan Uphoff _rm_unlock_hard(struct thread *td,struct rm_priotracker *tracker) 379f53d15feSStephan Uphoff { 380f53d15feSStephan Uphoff 381f53d15feSStephan Uphoff if (td->td_owepreempt) { 382f53d15feSStephan Uphoff td->td_critnest++; 383f53d15feSStephan Uphoff critical_exit(); 384f53d15feSStephan Uphoff } 385f53d15feSStephan Uphoff 386d02add54SRobert Watson if (!tracker->rmp_flags) 387f53d15feSStephan Uphoff return; 388f53d15feSStephan Uphoff 389f53d15feSStephan Uphoff mtx_lock_spin(&rm_spinlock); 390f53d15feSStephan Uphoff LIST_REMOVE(tracker, rmp_qentry); 391f53d15feSStephan Uphoff 392f53d15feSStephan Uphoff if (tracker->rmp_flags & RMPF_SIGNAL) { 393f53d15feSStephan Uphoff struct rmlock *rm; 394f53d15feSStephan Uphoff struct turnstile *ts; 395f53d15feSStephan Uphoff 396f53d15feSStephan Uphoff rm = tracker->rmp_rmlock; 397f53d15feSStephan Uphoff 398f53d15feSStephan Uphoff turnstile_chain_lock(&rm->lock_object); 399f53d15feSStephan Uphoff mtx_unlock_spin(&rm_spinlock); 400f53d15feSStephan Uphoff 401f53d15feSStephan Uphoff ts = turnstile_lookup(&rm->lock_object); 402f53d15feSStephan Uphoff 403f53d15feSStephan Uphoff turnstile_signal(ts, TS_EXCLUSIVE_QUEUE); 404f53d15feSStephan Uphoff turnstile_unpend(ts, TS_EXCLUSIVE_LOCK); 405f53d15feSStephan Uphoff turnstile_chain_unlock(&rm->lock_object); 406f53d15feSStephan Uphoff } else 407f53d15feSStephan Uphoff mtx_unlock_spin(&rm_spinlock); 408f53d15feSStephan Uphoff } 409f53d15feSStephan Uphoff 410f53d15feSStephan Uphoff void 411f53d15feSStephan Uphoff _rm_runlock(struct rmlock *rm, struct rm_priotracker *tracker) 412f53d15feSStephan Uphoff { 413f53d15feSStephan Uphoff struct pcpu *pc; 414f53d15feSStephan Uphoff struct thread *td = tracker->rmp_thread; 415f53d15feSStephan Uphoff 416f53d15feSStephan Uphoff td->td_critnest++; /* critical_enter(); */ 417f53d15feSStephan Uphoff pc = cpuid_to_pcpu[td->td_oncpu]; /* pcpu_find(td->td_oncpu); */ 418f53d15feSStephan Uphoff rm_tracker_remove(pc, tracker); 419f53d15feSStephan Uphoff td->td_critnest--; 42082b7a39cSRobert Watson sched_unpin(); 421f53d15feSStephan Uphoff 422f53d15feSStephan Uphoff if (0 == (td->td_owepreempt | tracker->rmp_flags)) 423f53d15feSStephan Uphoff return; 424f53d15feSStephan Uphoff 425f53d15feSStephan Uphoff _rm_unlock_hard(td, tracker); 426f53d15feSStephan Uphoff } 427f53d15feSStephan Uphoff 428f53d15feSStephan Uphoff void 429f53d15feSStephan Uphoff _rm_wlock(struct rmlock *rm) 430f53d15feSStephan Uphoff { 431f53d15feSStephan Uphoff struct rm_priotracker *prio; 432f53d15feSStephan Uphoff struct turnstile *ts; 433*71a19bdcSAttilio Rao cpuset_t readcpus; 434f53d15feSStephan Uphoff 43536058c09SMax Laier if (rm->lock_object.lo_flags & RM_SLEEPABLE) 43636058c09SMax Laier sx_xlock(&rm->rm_lock_sx); 43736058c09SMax Laier else 43836058c09SMax Laier mtx_lock(&rm->rm_lock_mtx); 439f53d15feSStephan Uphoff 440*71a19bdcSAttilio Rao if (CPU_CMP(&rm->rm_writecpus, &all_cpus)) { 441f53d15feSStephan Uphoff /* Get all read tokens back */ 442*71a19bdcSAttilio Rao readcpus = all_cpus; 443*71a19bdcSAttilio Rao CPU_NAND(&readcpus, &rm->rm_writecpus); 44436058c09SMax Laier rm->rm_writecpus = all_cpus; 445f53d15feSStephan Uphoff 446f53d15feSStephan Uphoff /* 44736058c09SMax Laier * Assumes rm->rm_writecpus update is visible on other CPUs 448d02add54SRobert Watson * before rm_cleanIPI is called. 449f53d15feSStephan Uphoff */ 450f53d15feSStephan Uphoff #ifdef SMP 45136058c09SMax Laier smp_rendezvous_cpus(readcpus, 45236058c09SMax Laier smp_no_rendevous_barrier, 453f53d15feSStephan Uphoff rm_cleanIPI, 454d02add54SRobert Watson smp_no_rendevous_barrier, 455d02add54SRobert Watson rm); 456f53d15feSStephan Uphoff 457f53d15feSStephan Uphoff #else 458f53d15feSStephan Uphoff rm_cleanIPI(rm); 459f53d15feSStephan Uphoff #endif 460f53d15feSStephan Uphoff 461f53d15feSStephan Uphoff mtx_lock_spin(&rm_spinlock); 462f53d15feSStephan Uphoff while ((prio = LIST_FIRST(&rm->rm_activeReaders)) != NULL) { 463f53d15feSStephan Uphoff ts = turnstile_trywait(&rm->lock_object); 464f53d15feSStephan Uphoff prio->rmp_flags = RMPF_ONQUEUE | RMPF_SIGNAL; 465f53d15feSStephan Uphoff mtx_unlock_spin(&rm_spinlock); 466f53d15feSStephan Uphoff turnstile_wait(ts, prio->rmp_thread, 467f53d15feSStephan Uphoff TS_EXCLUSIVE_QUEUE); 468f53d15feSStephan Uphoff mtx_lock_spin(&rm_spinlock); 469f53d15feSStephan Uphoff } 470f53d15feSStephan Uphoff mtx_unlock_spin(&rm_spinlock); 471f53d15feSStephan Uphoff } 472f53d15feSStephan Uphoff } 473f53d15feSStephan Uphoff 474f53d15feSStephan Uphoff void 475f53d15feSStephan Uphoff _rm_wunlock(struct rmlock *rm) 476f53d15feSStephan Uphoff { 477d02add54SRobert Watson 47836058c09SMax Laier if (rm->lock_object.lo_flags & RM_SLEEPABLE) 47936058c09SMax Laier sx_xunlock(&rm->rm_lock_sx); 48036058c09SMax Laier else 48136058c09SMax Laier mtx_unlock(&rm->rm_lock_mtx); 482f53d15feSStephan Uphoff } 483f53d15feSStephan Uphoff 484f53d15feSStephan Uphoff #ifdef LOCK_DEBUG 485f53d15feSStephan Uphoff 486f53d15feSStephan Uphoff void _rm_wlock_debug(struct rmlock *rm, const char *file, int line) 487f53d15feSStephan Uphoff { 488f53d15feSStephan Uphoff 489f53d15feSStephan Uphoff WITNESS_CHECKORDER(&rm->lock_object, LOP_NEWORDER | LOP_EXCLUSIVE, 49041313430SJohn Baldwin file, line, NULL); 491f53d15feSStephan Uphoff 492f53d15feSStephan Uphoff _rm_wlock(rm); 493f53d15feSStephan Uphoff 494f53d15feSStephan Uphoff LOCK_LOG_LOCK("RMWLOCK", &rm->lock_object, 0, 0, file, line); 495f53d15feSStephan Uphoff 49636058c09SMax Laier if (rm->lock_object.lo_flags & RM_SLEEPABLE) 49736058c09SMax Laier WITNESS_LOCK(&rm->rm_lock_sx.lock_object, LOP_EXCLUSIVE, 49836058c09SMax Laier file, line); 49936058c09SMax Laier else 500f53d15feSStephan Uphoff WITNESS_LOCK(&rm->lock_object, LOP_EXCLUSIVE, file, line); 501f53d15feSStephan Uphoff 502f53d15feSStephan Uphoff curthread->td_locks++; 503f53d15feSStephan Uphoff 504f53d15feSStephan Uphoff } 505f53d15feSStephan Uphoff 506d02add54SRobert Watson void 507d02add54SRobert Watson _rm_wunlock_debug(struct rmlock *rm, const char *file, int line) 508f53d15feSStephan Uphoff { 509d02add54SRobert Watson 510f53d15feSStephan Uphoff curthread->td_locks--; 51136058c09SMax Laier if (rm->lock_object.lo_flags & RM_SLEEPABLE) 51236058c09SMax Laier WITNESS_UNLOCK(&rm->rm_lock_sx.lock_object, LOP_EXCLUSIVE, 51336058c09SMax Laier file, line); 51436058c09SMax Laier else 515f53d15feSStephan Uphoff WITNESS_UNLOCK(&rm->lock_object, LOP_EXCLUSIVE, file, line); 516f53d15feSStephan Uphoff LOCK_LOG_LOCK("RMWUNLOCK", &rm->lock_object, 0, 0, file, line); 517f53d15feSStephan Uphoff _rm_wunlock(rm); 518f53d15feSStephan Uphoff } 519f53d15feSStephan Uphoff 52036058c09SMax Laier int 521f53d15feSStephan Uphoff _rm_rlock_debug(struct rmlock *rm, struct rm_priotracker *tracker, 52236058c09SMax Laier int trylock, const char *file, int line) 523f53d15feSStephan Uphoff { 52436058c09SMax Laier if (!trylock && (rm->lock_object.lo_flags & RM_SLEEPABLE)) 52536058c09SMax Laier WITNESS_CHECKORDER(&rm->rm_lock_sx.lock_object, LOP_NEWORDER, 52636058c09SMax Laier file, line, NULL); 52741313430SJohn Baldwin WITNESS_CHECKORDER(&rm->lock_object, LOP_NEWORDER, file, line, NULL); 528f53d15feSStephan Uphoff 52936058c09SMax Laier if (_rm_rlock(rm, tracker, trylock)) { 530f53d15feSStephan Uphoff LOCK_LOG_LOCK("RMRLOCK", &rm->lock_object, 0, 0, file, line); 531f53d15feSStephan Uphoff 532f53d15feSStephan Uphoff WITNESS_LOCK(&rm->lock_object, 0, file, line); 533f53d15feSStephan Uphoff 534f53d15feSStephan Uphoff curthread->td_locks++; 53536058c09SMax Laier 53636058c09SMax Laier return (1); 53736058c09SMax Laier } 53836058c09SMax Laier 53936058c09SMax Laier return (0); 540f53d15feSStephan Uphoff } 541f53d15feSStephan Uphoff 542f53d15feSStephan Uphoff void 543f53d15feSStephan Uphoff _rm_runlock_debug(struct rmlock *rm, struct rm_priotracker *tracker, 544d02add54SRobert Watson const char *file, int line) 545d02add54SRobert Watson { 546d02add54SRobert Watson 547f53d15feSStephan Uphoff curthread->td_locks--; 548f53d15feSStephan Uphoff WITNESS_UNLOCK(&rm->lock_object, 0, file, line); 549f53d15feSStephan Uphoff LOCK_LOG_LOCK("RMRUNLOCK", &rm->lock_object, 0, 0, file, line); 550f53d15feSStephan Uphoff _rm_runlock(rm, tracker); 551f53d15feSStephan Uphoff } 552f53d15feSStephan Uphoff 553f53d15feSStephan Uphoff #else 554d02add54SRobert Watson 555f53d15feSStephan Uphoff /* 556d02add54SRobert Watson * Just strip out file and line arguments if no lock debugging is enabled in 557d02add54SRobert Watson * the kernel - we are called from a kernel module. 558f53d15feSStephan Uphoff */ 559d02add54SRobert Watson void 560d02add54SRobert Watson _rm_wlock_debug(struct rmlock *rm, const char *file, int line) 561f53d15feSStephan Uphoff { 562d02add54SRobert Watson 563f53d15feSStephan Uphoff _rm_wlock(rm); 564f53d15feSStephan Uphoff } 565f53d15feSStephan Uphoff 566d02add54SRobert Watson void 567d02add54SRobert Watson _rm_wunlock_debug(struct rmlock *rm, const char *file, int line) 568f53d15feSStephan Uphoff { 569d02add54SRobert Watson 570f53d15feSStephan Uphoff _rm_wunlock(rm); 571f53d15feSStephan Uphoff } 572f53d15feSStephan Uphoff 57336058c09SMax Laier int 574f53d15feSStephan Uphoff _rm_rlock_debug(struct rmlock *rm, struct rm_priotracker *tracker, 57536058c09SMax Laier int trylock, const char *file, int line) 576f53d15feSStephan Uphoff { 577d02add54SRobert Watson 57836058c09SMax Laier return _rm_rlock(rm, tracker, trylock); 579f53d15feSStephan Uphoff } 580f53d15feSStephan Uphoff 581f53d15feSStephan Uphoff void 582f53d15feSStephan Uphoff _rm_runlock_debug(struct rmlock *rm, struct rm_priotracker *tracker, 5831191932aSRobert Watson const char *file, int line) 5841191932aSRobert Watson { 585d02add54SRobert Watson 586f53d15feSStephan Uphoff _rm_runlock(rm, tracker); 587f53d15feSStephan Uphoff } 588f53d15feSStephan Uphoff 589f53d15feSStephan Uphoff #endif 590