Deleted Added
full compact
kern_rwlock.c (170295) kern_rwlock.c (171052)
1/*-
2 * Copyright (c) 2006 John Baldwin <jhb@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

--- 18 unchanged lines hidden (view full) ---

27 * SUCH DAMAGE.
28 */
29
30/*
31 * Machine independent bits of reader/writer lock implementation.
32 */
33
34#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2006 John Baldwin <jhb@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

--- 18 unchanged lines hidden (view full) ---

27 * SUCH DAMAGE.
28 */
29
30/*
31 * Machine independent bits of reader/writer lock implementation.
32 */
33
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD: head/sys/kern/kern_rwlock.c 170295 2007-06-04 23:51:44Z jeff $");
35__FBSDID("$FreeBSD: head/sys/kern/kern_rwlock.c 171052 2007-06-26 21:31:56Z attilio $");
36
37#include "opt_ddb.h"
38#include "opt_no_adaptive_rwlocks.h"
39
40#include <sys/param.h>
41#include <sys/ktr.h>
42#include <sys/lock.h>
43#include <sys/mutex.h>
44#include <sys/proc.h>
45#include <sys/rwlock.h>
46#include <sys/systm.h>
47#include <sys/turnstile.h>
48#include <sys/lock_profile.h>
49#include <machine/cpu.h>
50
36
37#include "opt_ddb.h"
38#include "opt_no_adaptive_rwlocks.h"
39
40#include <sys/param.h>
41#include <sys/ktr.h>
42#include <sys/lock.h>
43#include <sys/mutex.h>
44#include <sys/proc.h>
45#include <sys/rwlock.h>
46#include <sys/systm.h>
47#include <sys/turnstile.h>
48#include <sys/lock_profile.h>
49#include <machine/cpu.h>
50
51CTASSERT((RW_RECURSE & LO_CLASSFLAGS) == RW_RECURSE);
52
51#if defined(SMP) && !defined(NO_ADAPTIVE_RWLOCKS)
52#define ADAPTIVE_RWLOCKS
53#endif
54
55#ifdef DDB
56#include <ddb/ddb.h>
57
58static void db_show_rwlock(struct lock_object *lock);

--- 15 unchanged lines hidden (view full) ---

74 * Return a pointer to the owning thread if the lock is write-locked or
75 * NULL if the lock is unlocked or read-locked.
76 */
77#define rw_wowner(rw) \
78 ((rw)->rw_lock & RW_LOCK_READ ? NULL : \
79 (struct thread *)RW_OWNER((rw)->rw_lock))
80
81/*
53#if defined(SMP) && !defined(NO_ADAPTIVE_RWLOCKS)
54#define ADAPTIVE_RWLOCKS
55#endif
56
57#ifdef DDB
58#include <ddb/ddb.h>
59
60static void db_show_rwlock(struct lock_object *lock);

--- 15 unchanged lines hidden (view full) ---

76 * Return a pointer to the owning thread if the lock is write-locked or
77 * NULL if the lock is unlocked or read-locked.
78 */
79#define rw_wowner(rw) \
80 ((rw)->rw_lock & RW_LOCK_READ ? NULL : \
81 (struct thread *)RW_OWNER((rw)->rw_lock))
82
83/*
84 * Returns if a write owner is recursed. Write ownership is not assured
85 * here and should be previously checked.
86 */
87#define rw_recursed(rw) ((rw)->rw_recurse != 0)
88
89/*
90 * Return true if curthread helds the lock.
91 */
92#define rw_wlocked(rw) (rw_wowner((rw)) == curthread)
93
94/*
82 * Return a pointer to the owning thread for this lock who should receive
83 * any priority lent by threads that block on this lock. Currently this
84 * is identical to rw_wowner().
85 */
86#define rw_owner(rw) rw_wowner(rw)
87
88#ifndef INVARIANTS
89#define _rw_assert(rw, what, file, line)

--- 23 unchanged lines hidden (view full) ---

113 return (0);
114 } else {
115 rw_wunlock(rw);
116 return (1);
117 }
118}
119
120void
95 * Return a pointer to the owning thread for this lock who should receive
96 * any priority lent by threads that block on this lock. Currently this
97 * is identical to rw_wowner().
98 */
99#define rw_owner(rw) rw_wowner(rw)
100
101#ifndef INVARIANTS
102#define _rw_assert(rw, what, file, line)

--- 23 unchanged lines hidden (view full) ---

126 return (0);
127 } else {
128 rw_wunlock(rw);
129 return (1);
130 }
131}
132
133void
121rw_init(struct rwlock *rw, const char *name)
134rw_init_flags(struct rwlock *rw, const char *name, int opts)
122{
135{
136 int flags;
123
137
124 rw->rw_lock = RW_UNLOCKED;
138 MPASS((opts & ~(RW_DUPOK | RW_NOPROFILE | RW_NOWITNESS | RW_QUIET |
139 RW_RECURSE)) == 0);
125
140
126 lock_init(&rw->lock_object, &lock_class_rw, name, NULL, LO_WITNESS |
127 LO_RECURSABLE | LO_UPGRADABLE);
141 flags = LO_UPGRADABLE | LO_RECURSABLE;
142 if (opts & RW_DUPOK)
143 flags |= LO_DUPOK;
144 if (opts & RW_NOPROFILE)
145 flags |= LO_NOPROFILE;
146 if (!(opts & RW_NOWITNESS))
147 flags |= LO_WITNESS;
148 if (opts & RW_QUIET)
149 flags |= LO_QUIET;
150 flags |= opts & RW_RECURSE;
151
152 rw->rw_lock = RW_UNLOCKED;
153 rw->rw_recurse = 0;
154 lock_init(&rw->lock_object, &lock_class_rw, name, NULL, flags);
128}
129
130void
131rw_destroy(struct rwlock *rw)
132{
133
134 KASSERT(rw->rw_lock == RW_UNLOCKED, ("rw lock not unlocked"));
155}
156
157void
158rw_destroy(struct rwlock *rw)
159{
160
161 KASSERT(rw->rw_lock == RW_UNLOCKED, ("rw lock not unlocked"));
162 KASSERT(rw->rw_recurse == 0, ("rw lock still recursed"));
135 rw->rw_lock = RW_DESTROYED;
136 lock_destroy(&rw->lock_object);
137}
138
139void
140rw_sysinit(void *arg)
141{
142 struct rw_args *args = arg;

--- 16 unchanged lines hidden (view full) ---

159 KASSERT(rw->rw_lock != RW_DESTROYED,
160 ("rw_wlock() of destroyed rwlock @ %s:%d", file, line));
161 KASSERT(rw_wowner(rw) != curthread,
162 ("%s (%s): wlock already held @ %s:%d", __func__,
163 rw->lock_object.lo_name, file, line));
164 WITNESS_CHECKORDER(&rw->lock_object, LOP_NEWORDER | LOP_EXCLUSIVE, file,
165 line);
166 __rw_wlock(rw, curthread, file, line);
163 rw->rw_lock = RW_DESTROYED;
164 lock_destroy(&rw->lock_object);
165}
166
167void
168rw_sysinit(void *arg)
169{
170 struct rw_args *args = arg;

--- 16 unchanged lines hidden (view full) ---

187 KASSERT(rw->rw_lock != RW_DESTROYED,
188 ("rw_wlock() of destroyed rwlock @ %s:%d", file, line));
189 KASSERT(rw_wowner(rw) != curthread,
190 ("%s (%s): wlock already held @ %s:%d", __func__,
191 rw->lock_object.lo_name, file, line));
192 WITNESS_CHECKORDER(&rw->lock_object, LOP_NEWORDER | LOP_EXCLUSIVE, file,
193 line);
194 __rw_wlock(rw, curthread, file, line);
167 LOCK_LOG_LOCK("WLOCK", &rw->lock_object, 0, 0, file, line);
195 LOCK_LOG_LOCK("WLOCK", &rw->lock_object, 0, rw->rw_recurse, file, line);
168 WITNESS_LOCK(&rw->lock_object, LOP_EXCLUSIVE, file, line);
169 curthread->td_locks++;
170}
171
172void
173_rw_wunlock(struct rwlock *rw, const char *file, int line)
174{
175
176 MPASS(curthread != NULL);
177 KASSERT(rw->rw_lock != RW_DESTROYED,
178 ("rw_wunlock() of destroyed rwlock @ %s:%d", file, line));
179 _rw_assert(rw, RA_WLOCKED, file, line);
180 curthread->td_locks--;
181 WITNESS_UNLOCK(&rw->lock_object, LOP_EXCLUSIVE, file, line);
196 WITNESS_LOCK(&rw->lock_object, LOP_EXCLUSIVE, file, line);
197 curthread->td_locks++;
198}
199
200void
201_rw_wunlock(struct rwlock *rw, const char *file, int line)
202{
203
204 MPASS(curthread != NULL);
205 KASSERT(rw->rw_lock != RW_DESTROYED,
206 ("rw_wunlock() of destroyed rwlock @ %s:%d", file, line));
207 _rw_assert(rw, RA_WLOCKED, file, line);
208 curthread->td_locks--;
209 WITNESS_UNLOCK(&rw->lock_object, LOP_EXCLUSIVE, file, line);
182 LOCK_LOG_LOCK("WUNLOCK", &rw->lock_object, 0, 0, file, line);
183 lock_profile_release_lock(&rw->lock_object);
210 LOCK_LOG_LOCK("WUNLOCK", &rw->lock_object, 0, rw->rw_recurse, file,
211 line);
212 if (!rw_recursed(rw))
213 lock_profile_release_lock(&rw->lock_object);
184 __rw_wunlock(rw, curthread, file, line);
185}
186
187void
188_rw_rlock(struct rwlock *rw, const char *file, int line)
189{
190 struct turnstile *ts;
191#ifdef ADAPTIVE_RWLOCKS

--- 269 unchanged lines hidden (view full) ---

461_rw_wlock_hard(struct rwlock *rw, uintptr_t tid, const char *file, int line)
462{
463 struct turnstile *ts;
464#ifdef ADAPTIVE_RWLOCKS
465 volatile struct thread *owner;
466#endif
467 uintptr_t v;
468
214 __rw_wunlock(rw, curthread, file, line);
215}
216
217void
218_rw_rlock(struct rwlock *rw, const char *file, int line)
219{
220 struct turnstile *ts;
221#ifdef ADAPTIVE_RWLOCKS

--- 269 unchanged lines hidden (view full) ---

491_rw_wlock_hard(struct rwlock *rw, uintptr_t tid, const char *file, int line)
492{
493 struct turnstile *ts;
494#ifdef ADAPTIVE_RWLOCKS
495 volatile struct thread *owner;
496#endif
497 uintptr_t v;
498
499 if (rw_wlocked(rw)) {
500 KASSERT(rw->lock_object.lo_flags & RW_RECURSE,
501 ("%s: recursing but non-recursive rw %s @ %s:%d\n",
502 __func__, rw->lock_object.lo_name, file, line));
503 rw->rw_recurse++;
504 atomic_set_ptr(&rw->rw_lock, RW_LOCK_RECURSED);
505 if (LOCK_LOG_TEST(&rw->lock_object, 0))
506 CTR2(KTR_LOCK, "%s: %p recursing", __func__, rw);
507 return;
508 }
509
469 if (LOCK_LOG_TEST(&rw->lock_object, 0))
470 CTR5(KTR_LOCK, "%s: %s contested (lock=%p) at %s:%d", __func__,
471 rw->lock_object.lo_name, (void *)rw->rw_lock, file, line);
472
473 while (!_rw_write_lock(rw, tid)) {
474 ts = turnstile_trywait(&rw->lock_object);
475 v = rw->rw_lock;
476

--- 88 unchanged lines hidden (view full) ---

565 */
566void
567_rw_wunlock_hard(struct rwlock *rw, uintptr_t tid, const char *file, int line)
568{
569 struct turnstile *ts;
570 uintptr_t v;
571 int queue;
572
510 if (LOCK_LOG_TEST(&rw->lock_object, 0))
511 CTR5(KTR_LOCK, "%s: %s contested (lock=%p) at %s:%d", __func__,
512 rw->lock_object.lo_name, (void *)rw->rw_lock, file, line);
513
514 while (!_rw_write_lock(rw, tid)) {
515 ts = turnstile_trywait(&rw->lock_object);
516 v = rw->rw_lock;
517

--- 88 unchanged lines hidden (view full) ---

606 */
607void
608_rw_wunlock_hard(struct rwlock *rw, uintptr_t tid, const char *file, int line)
609{
610 struct turnstile *ts;
611 uintptr_t v;
612 int queue;
613
614 if (rw_wlocked(rw) && rw_recursed(rw)) {
615 if ((--rw->rw_recurse) == 0)
616 atomic_clear_ptr(&rw->rw_lock, RW_LOCK_RECURSED);
617 if (LOCK_LOG_TEST(&rw->lock_object, 0))
618 CTR2(KTR_LOCK, "%s: %p unrecursing", __func__, rw);
619 return;
620 }
621
573 KASSERT(rw->rw_lock & (RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS),
574 ("%s: neither of the waiter flags are set", __func__));
575
576 if (LOCK_LOG_TEST(&rw->lock_object, 0))
577 CTR2(KTR_LOCK, "%s: %p contested", __func__, rw);
578
579 turnstile_chain_lock(&rw->lock_object);
580 ts = turnstile_lookup(&rw->lock_object);

--- 146 unchanged lines hidden (view full) ---

727void
728_rw_downgrade(struct rwlock *rw, const char *file, int line)
729{
730 struct turnstile *ts;
731 uintptr_t tid, v;
732
733 KASSERT(rw->rw_lock != RW_DESTROYED,
734 ("rw_downgrade() of destroyed rwlock @ %s:%d", file, line));
622 KASSERT(rw->rw_lock & (RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS),
623 ("%s: neither of the waiter flags are set", __func__));
624
625 if (LOCK_LOG_TEST(&rw->lock_object, 0))
626 CTR2(KTR_LOCK, "%s: %p contested", __func__, rw);
627
628 turnstile_chain_lock(&rw->lock_object);
629 ts = turnstile_lookup(&rw->lock_object);

--- 146 unchanged lines hidden (view full) ---

776void
777_rw_downgrade(struct rwlock *rw, const char *file, int line)
778{
779 struct turnstile *ts;
780 uintptr_t tid, v;
781
782 KASSERT(rw->rw_lock != RW_DESTROYED,
783 ("rw_downgrade() of destroyed rwlock @ %s:%d", file, line));
735 _rw_assert(rw, RA_WLOCKED, file, line);
784 _rw_assert(rw, RA_WLOCKED | RA_NOTRECURSED, file, line);
785#ifndef INVARIANTS
786 if (rw_recursed(rw))
787 panic("downgrade of a recursed lock");
788#endif
736
737 WITNESS_DOWNGRADE(&rw->lock_object, 0, file, line);
738
739 /*
740 * Convert from a writer to a single reader. First we handle
741 * the easy case with no waiters. If there are any waiters, we
742 * lock the turnstile, "disown" the lock, and awaken any read
743 * waiters.

--- 60 unchanged lines hidden (view full) ---

804void
805_rw_assert(struct rwlock *rw, int what, const char *file, int line)
806{
807
808 if (panicstr != NULL)
809 return;
810 switch (what) {
811 case RA_LOCKED:
789
790 WITNESS_DOWNGRADE(&rw->lock_object, 0, file, line);
791
792 /*
793 * Convert from a writer to a single reader. First we handle
794 * the easy case with no waiters. If there are any waiters, we
795 * lock the turnstile, "disown" the lock, and awaken any read
796 * waiters.

--- 60 unchanged lines hidden (view full) ---

857void
858_rw_assert(struct rwlock *rw, int what, const char *file, int line)
859{
860
861 if (panicstr != NULL)
862 return;
863 switch (what) {
864 case RA_LOCKED:
812 case RA_LOCKED | LA_NOTRECURSED:
865 case RA_LOCKED | RA_RECURSED:
866 case RA_LOCKED | RA_NOTRECURSED:
813 case RA_RLOCKED:
814#ifdef WITNESS
815 witness_assert(&rw->lock_object, what, file, line);
816#else
817 /*
818 * If some other thread has a write lock or we have one
819 * and are asserting a read lock, fail. Also, if no one
820 * has a lock at all, fail.
821 */
822 if (rw->rw_lock == RW_UNLOCKED ||
823 (!(rw->rw_lock & RW_LOCK_READ) && (what == RA_RLOCKED ||
824 rw_wowner(rw) != curthread)))
825 panic("Lock %s not %slocked @ %s:%d\n",
826 rw->lock_object.lo_name, (what == RA_RLOCKED) ?
827 "read " : "", file, line);
867 case RA_RLOCKED:
868#ifdef WITNESS
869 witness_assert(&rw->lock_object, what, file, line);
870#else
871 /*
872 * If some other thread has a write lock or we have one
873 * and are asserting a read lock, fail. Also, if no one
874 * has a lock at all, fail.
875 */
876 if (rw->rw_lock == RW_UNLOCKED ||
877 (!(rw->rw_lock & RW_LOCK_READ) && (what == RA_RLOCKED ||
878 rw_wowner(rw) != curthread)))
879 panic("Lock %s not %slocked @ %s:%d\n",
880 rw->lock_object.lo_name, (what == RA_RLOCKED) ?
881 "read " : "", file, line);
882
883 if (!(rw->rw_lock & RW_LOCK_READ)) {
884 if (rw_recursed(rw)) {
885 if (what & RA_NOTRECURSED)
886 panic("Lock %s recursed @ %s:%d\n",
887 rw->lock_object.lo_name, file,
888 line);
889 } else if (what & RA_RECURSED)
890 panic("Lock %s not recursed @ %s:%d\n",
891 rw->lock_object.lo_name, file, line);
892 }
828#endif
829 break;
830 case RA_WLOCKED:
893#endif
894 break;
895 case RA_WLOCKED:
896 case RA_WLOCKED | RA_RECURSED:
897 case RA_WLOCKED | RA_NOTRECURSED:
831 if (rw_wowner(rw) != curthread)
832 panic("Lock %s not exclusively locked @ %s:%d\n",
833 rw->lock_object.lo_name, file, line);
898 if (rw_wowner(rw) != curthread)
899 panic("Lock %s not exclusively locked @ %s:%d\n",
900 rw->lock_object.lo_name, file, line);
901 if (rw_recursed(rw)) {
902 if (what & RA_NOTRECURSED)
903 panic("Lock %s recursed @ %s:%d\n",
904 rw->lock_object.lo_name, file, line);
905 } else if (what & RA_RECURSED)
906 panic("Lock %s not recursed @ %s:%d\n",
907 rw->lock_object.lo_name, file, line);
834 break;
835 case RA_UNLOCKED:
836#ifdef WITNESS
837 witness_assert(&rw->lock_object, what, file, line);
838#else
839 /*
840 * If we hold a write lock fail. We can't reliably check
841 * to see if we hold a read lock or not.

--- 27 unchanged lines hidden (view full) ---

869 return;
870 } else if (rw->rw_lock & RW_LOCK_READ)
871 db_printf("RLOCK: %ju locks\n",
872 (uintmax_t)(RW_READERS(rw->rw_lock)));
873 else {
874 td = rw_wowner(rw);
875 db_printf("WLOCK: %p (tid %d, pid %d, \"%s\")\n", td,
876 td->td_tid, td->td_proc->p_pid, td->td_proc->p_comm);
908 break;
909 case RA_UNLOCKED:
910#ifdef WITNESS
911 witness_assert(&rw->lock_object, what, file, line);
912#else
913 /*
914 * If we hold a write lock fail. We can't reliably check
915 * to see if we hold a read lock or not.

--- 27 unchanged lines hidden (view full) ---

943 return;
944 } else if (rw->rw_lock & RW_LOCK_READ)
945 db_printf("RLOCK: %ju locks\n",
946 (uintmax_t)(RW_READERS(rw->rw_lock)));
947 else {
948 td = rw_wowner(rw);
949 db_printf("WLOCK: %p (tid %d, pid %d, \"%s\")\n", td,
950 td->td_tid, td->td_proc->p_pid, td->td_proc->p_comm);
951 if (rw_recursed(rw))
952 db_printf(" recursed: %u\n", rw->rw_recurse);
877 }
878 db_printf(" waiters: ");
879 switch (rw->rw_lock & (RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS)) {
880 case RW_LOCK_READ_WAITERS:
881 db_printf("readers\n");
882 break;
883 case RW_LOCK_WRITE_WAITERS:
884 db_printf("writers\n");
885 break;
886 case RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS:
887 db_printf("readers and writers\n");
888 break;
889 default:
890 db_printf("none\n");
891 break;
892 }
893}
894
895#endif
953 }
954 db_printf(" waiters: ");
955 switch (rw->rw_lock & (RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS)) {
956 case RW_LOCK_READ_WAITERS:
957 db_printf("readers\n");
958 break;
959 case RW_LOCK_WRITE_WAITERS:
960 db_printf("writers\n");
961 break;
962 case RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS:
963 db_printf("readers and writers\n");
964 break;
965 default:
966 db_printf("none\n");
967 break;
968 }
969}
970
971#endif