1 /* 2 * CDDL HEADER START 3 * 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. 8 * 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. 13 * 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] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/rwstlock.h> 30 #include <sys/errno.h> 31 #include <sys/debug.h> 32 #include <sys/lockstat.h> 33 #include <sys/sysmacros.h> 34 #include <sys/condvar_impl.h> 35 36 /* 37 * Alternate rwlock that is interruptible and can be released by a thread 38 * other than the one that acquired the lock. 39 * 40 * There is no priority inheritance mechanism for these locks. 41 * Writers have priority over readers, so reader starvation is possible. 42 */ 43 44 /* 45 * Common code to grab a lock. There are three cases: 46 * 47 * (1) If RWST_TRYENTER is set, we try the lock without blocking. 48 * In this case we return 1 on success, 0 on failure. 49 * 50 * (2) If RWST_SIG is set, we block interruptibly until we get the lock. 51 * In this case we return 0 on success, EINTR if we're interrupted. 52 * 53 * (3) If neither flag is set, we block uninterruptibly until we get the lock. 54 * In this case we return 0 (we always succeed). 55 */ 56 static int 57 rwst_enter_common(rwstlock_t *l, krw_t rw, int flags) 58 { 59 hrtime_t sleep_time; 60 int writer; 61 intptr_t readers; 62 63 mutex_enter(&l->rwst_lock); 64 if (rw == RW_READER) { 65 while (RWST_WRITE_HELD(l) || RWST_WRITE_WANTED(l)) { 66 67 if (flags & RWST_TRYENTER) { 68 mutex_exit(&l->rwst_lock); 69 return (0); 70 } 71 if (panicstr) 72 return (0); 73 74 if (RWST_WRITE_HELD(l)) { 75 writer = 1; 76 readers = 0; 77 } else { 78 writer = 0; 79 readers = l->rwst_count; 80 } 81 sleep_time = -gethrtime(); 82 if (!RWST_READ_WAIT(l, flags)) { 83 mutex_exit(&l->rwst_lock); 84 return (EINTR); 85 } 86 sleep_time += gethrtime(); 87 LOCKSTAT_RECORD4(LS_RW_ENTER_BLOCK, l, sleep_time, rw, 88 writer, readers); 89 } 90 RWST_READ_ENTER(l); 91 LOCKSTAT_RECORD(LS_RW_ENTER_ACQUIRE, l, rw); 92 } else { 93 ASSERT(rw == RW_WRITER); 94 while (RWST_HELD(l)) { 95 if (flags & RWST_TRYENTER) { 96 mutex_exit(&l->rwst_lock); 97 return (0); 98 } 99 if (panicstr) 100 return (0); 101 if (RWST_WRITE_HELD(l)) { 102 writer = 1; 103 readers = 0; 104 } else { 105 writer = 0; 106 readers = l->rwst_count; 107 } 108 sleep_time = -gethrtime(); 109 if (!RWST_WRITE_WAIT(l, flags)) { 110 if (!RWST_WRITE_HELD(l) && 111 !RWST_WRITE_WANTED(l)) 112 RWST_READ_WAKE_ALL(l); 113 mutex_exit(&l->rwst_lock); 114 return (EINTR); 115 } 116 sleep_time += gethrtime(); 117 LOCKSTAT_RECORD4(LS_RW_ENTER_BLOCK, l, sleep_time, rw, 118 writer, readers); 119 } 120 RWST_WRITE_ENTER(l); 121 LOCKSTAT_RECORD(LS_RW_ENTER_ACQUIRE, l, rw); 122 } 123 mutex_exit(&l->rwst_lock); 124 return (flags & RWST_TRYENTER); 125 } 126 127 void 128 rwst_exit(rwstlock_t *l) 129 { 130 mutex_enter(&l->rwst_lock); 131 if (RWST_WRITE_HELD(l)) { 132 LOCKSTAT_RECORD(LS_RW_EXIT_RELEASE, l, RW_WRITER); 133 RWST_WRITE_EXIT(l); 134 } else { 135 ASSERT(RWST_READ_HELD(l)); 136 LOCKSTAT_RECORD(LS_RW_EXIT_RELEASE, l, RW_READER); 137 RWST_READ_EXIT(l); 138 } 139 if (!RWST_WRITE_WANTED(l)) 140 RWST_READ_WAKE_ALL(l); 141 else if (!RWST_HELD(l)) 142 RWST_WRITE_WAKE_ONE(l); 143 mutex_exit(&l->rwst_lock); 144 } 145 146 void 147 rwst_enter(rwstlock_t *l, krw_t rw) 148 { 149 (void) rwst_enter_common(l, rw, 0); 150 } 151 152 int 153 rwst_enter_sig(rwstlock_t *l, krw_t rw) 154 { 155 return (rwst_enter_common(l, rw, RWST_SIG)); 156 } 157 158 int 159 rwst_tryenter(rwstlock_t *l, krw_t rw) 160 { 161 return (rwst_enter_common(l, rw, RWST_TRYENTER)); 162 } 163 164 int 165 rwst_lock_held(rwstlock_t *l, krw_t rw) 166 { 167 if (rw == RW_READER) 168 return (RWST_READ_HELD(l)); 169 ASSERT(rw == RW_WRITER); 170 return (RWST_WRITE_OWNER(l)); 171 } 172 173 /*ARGSUSED*/ 174 void 175 rwst_init(rwstlock_t *l, char *name, krw_type_t krw_t, void *arg) 176 { 177 l->rwst_count = 0; 178 mutex_init(&l->rwst_lock, NULL, MUTEX_DEFAULT, NULL); 179 cv_init(&l->rwst_rcv, NULL, CV_DEFAULT, NULL); 180 cv_init(&l->rwst_wcv, NULL, CV_DEFAULT, NULL); 181 } 182 183 void 184 rwst_destroy(rwstlock_t *l) 185 { 186 ASSERT(l->rwst_count == 0); 187 mutex_destroy(&l->rwst_lock); 188 cv_destroy(&l->rwst_rcv); 189 cv_destroy(&l->rwst_wcv); 190 } 191 192 struct _kthread * 193 rwst_owner(rwstlock_t *l) 194 { 195 return (RWST_OWNER(l)); 196 } 197