Merge branch 'black_magic'
[unleashed.git] / kernel / os / rwstlock.c
blob85f1ef6e05f76e291dd093867a4fe9ca41a1c1af
1 /*
2 * CDDL HEADER START
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
7 * with the License.
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]
20 * CDDL HEADER END
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).
60 static int
61 rwst_enter_common(rwstlock_t *l, krw_t rw, int flags)
63 hrtime_t sleep_time;
64 int writer;
65 intptr_t readers;
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);
74 return (0);
76 if (panicstr)
77 return (0);
79 if (RWST_WRITE_HELD(l)) {
80 writer = 1;
81 readers = 0;
82 } else {
83 writer = 0;
84 readers = l->rwst_count;
86 sleep_time = -gethrtime();
87 if (!RWST_READ_WAIT(l, flags)) {
88 mutex_exit(&l->rwst_lock);
89 return (EINTR);
91 sleep_time += gethrtime();
92 LOCKSTAT_RECORD4(LS_RW_ENTER_BLOCK, l, sleep_time, rw,
93 writer, readers);
95 RWST_READ_ENTER(l);
96 LOCKSTAT_RECORD(LS_RW_ENTER_ACQUIRE, l, rw);
97 } else {
98 ASSERT(rw == RW_WRITER);
99 while (RWST_HELD(l)) {
100 if (flags & RWST_TRYENTER) {
101 mutex_exit(&l->rwst_lock);
102 return (0);
104 if (panicstr)
105 return (0);
106 if (RWST_WRITE_HELD(l)) {
107 writer = 1;
108 readers = 0;
109 } else {
110 writer = 0;
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);
119 return (EINTR);
121 sleep_time += gethrtime();
122 LOCKSTAT_RECORD4(LS_RW_ENTER_BLOCK, l, sleep_time, rw,
123 writer, readers);
125 RWST_WRITE_ENTER(l);
126 LOCKSTAT_RECORD(LS_RW_ENTER_ACQUIRE, l, rw);
128 mutex_exit(&l->rwst_lock);
129 return (flags & RWST_TRYENTER);
132 void
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);
138 RWST_WRITE_EXIT(l);
139 } else {
140 ASSERT(RWST_READ_HELD(l));
141 LOCKSTAT_RECORD(LS_RW_EXIT_RELEASE, l, RW_READER);
142 RWST_READ_EXIT(l);
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);
151 void
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)
172 if (rw != RW_WRITER)
173 return (RWST_READ_HELD(l));
174 ASSERT(rw == RW_WRITER);
175 return (RWST_WRITE_OWNER(l));
178 /*ARGSUSED*/
179 void
180 rwst_init(rwstlock_t *l, char *name, krw_type_t krw_t, void *arg)
182 l->rwst_count = 0;
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);
188 void
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);
197 struct _kthread *
198 rwst_owner(rwstlock_t *l)
200 return (RWST_OWNER(l));