4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
31 #include <sys/rwstlock.h>
32 #include <sys/errno.h>
33 #include <sys/debug.h>
34 #include <sys/lockstat.h>
35 #include <sys/sysmacros.h>
36 #include <sys/condvar_impl.h>
39 * Alternate rwlock that is interruptible and can be released by a thread
40 * other than the one that acquired the lock.
42 * There is no priority inheritance mechanism for these locks.
43 * For RW_READER, writers have priority over readers, so reader starvation
44 * is possible; as with rwlocks, this behavior may be overridden by
45 * specifying RW_READER_STARVEWRITER.
49 * Common code to grab a lock. There are three cases:
51 * (1) If RWST_TRYENTER is set, we try the lock without blocking.
52 * In this case we return 1 on success, 0 on failure.
54 * (2) If RWST_SIG is set, we block interruptibly until we get the lock.
55 * In this case we return 0 on success, EINTR if we're interrupted.
57 * (3) If neither flag is set, we block uninterruptibly until we get the lock.
58 * In this case we return 0 (we always succeed).
61 rwst_enter_common(rwstlock_t
*l
, krw_t rw
, int flags
)
67 mutex_enter(&l
->rwst_lock
);
68 if (rw
== RW_READER
|| rw
== RW_READER_STARVEWRITER
) {
69 while (RWST_WRITE_HELD(l
) ||
70 (rw
!= RW_READER_STARVEWRITER
&& RWST_WRITE_WANTED(l
))) {
72 if (flags
& RWST_TRYENTER
) {
73 mutex_exit(&l
->rwst_lock
);
79 if (RWST_WRITE_HELD(l
)) {
84 readers
= l
->rwst_count
;
86 sleep_time
= -gethrtime();
87 if (!RWST_READ_WAIT(l
, flags
)) {
88 mutex_exit(&l
->rwst_lock
);
91 sleep_time
+= gethrtime();
92 LOCKSTAT_RECORD4(LS_RW_ENTER_BLOCK
, l
, sleep_time
, rw
,
96 LOCKSTAT_RECORD(LS_RW_ENTER_ACQUIRE
, l
, rw
);
98 ASSERT(rw
== RW_WRITER
);
99 while (RWST_HELD(l
)) {
100 if (flags
& RWST_TRYENTER
) {
101 mutex_exit(&l
->rwst_lock
);
106 if (RWST_WRITE_HELD(l
)) {
111 readers
= l
->rwst_count
;
113 sleep_time
= -gethrtime();
114 if (!RWST_WRITE_WAIT(l
, flags
)) {
115 if (!RWST_WRITE_HELD(l
) &&
116 !RWST_WRITE_WANTED(l
))
117 RWST_READ_WAKE_ALL(l
);
118 mutex_exit(&l
->rwst_lock
);
121 sleep_time
+= gethrtime();
122 LOCKSTAT_RECORD4(LS_RW_ENTER_BLOCK
, l
, sleep_time
, rw
,
126 LOCKSTAT_RECORD(LS_RW_ENTER_ACQUIRE
, l
, rw
);
128 mutex_exit(&l
->rwst_lock
);
129 return (flags
& RWST_TRYENTER
);
133 rwst_exit(rwstlock_t
*l
)
135 mutex_enter(&l
->rwst_lock
);
136 if (RWST_WRITE_HELD(l
)) {
137 LOCKSTAT_RECORD(LS_RW_EXIT_RELEASE
, l
, RW_WRITER
);
140 ASSERT(RWST_READ_HELD(l
));
141 LOCKSTAT_RECORD(LS_RW_EXIT_RELEASE
, l
, RW_READER
);
144 if (!RWST_WRITE_WANTED(l
))
145 RWST_READ_WAKE_ALL(l
);
146 else if (!RWST_HELD(l
))
147 RWST_WRITE_WAKE_ONE(l
);
148 mutex_exit(&l
->rwst_lock
);
152 rwst_enter(rwstlock_t
*l
, krw_t rw
)
154 (void) rwst_enter_common(l
, rw
, 0);
158 rwst_enter_sig(rwstlock_t
*l
, krw_t rw
)
160 return (rwst_enter_common(l
, rw
, RWST_SIG
));
164 rwst_tryenter(rwstlock_t
*l
, krw_t rw
)
166 return (rwst_enter_common(l
, rw
, RWST_TRYENTER
));
170 rwst_lock_held(rwstlock_t
*l
, krw_t rw
)
173 return (RWST_READ_HELD(l
));
174 ASSERT(rw
== RW_WRITER
);
175 return (RWST_WRITE_OWNER(l
));
180 rwst_init(rwstlock_t
*l
, char *name
, krw_type_t krw_t
, void *arg
)
183 mutex_init(&l
->rwst_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
184 cv_init(&l
->rwst_rcv
, NULL
, CV_DEFAULT
, NULL
);
185 cv_init(&l
->rwst_wcv
, NULL
, CV_DEFAULT
, NULL
);
189 rwst_destroy(rwstlock_t
*l
)
191 ASSERT(l
->rwst_count
== 0);
192 mutex_destroy(&l
->rwst_lock
);
193 cv_destroy(&l
->rwst_rcv
);
194 cv_destroy(&l
->rwst_wcv
);
198 rwst_owner(rwstlock_t
*l
)
200 return (RWST_OWNER(l
));