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 /* 28 * Copyright (c) 2013, Joyent, Inc. All rights reserved. 29 */ 30 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> 37 38 /* 39 * Alternate rwlock that is interruptible and can be released by a thread 40 * other than the one that acquired the lock. 41 * 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. 46 */ 47 48 /* 49 * Common code to grab a lock. There are three cases: 50 * 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. 53 * 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. 56 * 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). 59 */ 60 static int 61 rwst_enter_common(rwstlock_t *l, krw_t rw, int flags) 62 { 63 hrtime_t sleep_time; 64 int writer; 65 intptr_t readers; 66 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))) { 71 72 if (flags & RWST_TRYENTER) { 73 mutex_exit(&l->rwst_lock); 74 return (0); 75 } 76 if (panicstr) 77 return (0); 78 79 if (RWST_WRITE_HELD(l)) { 80 writer = 1; 81 readers = 0; 82 } else { 83 writer = 0; 84 readers = l->rwst_count; 85 } 86 sleep_time = -gethrtime(); 87 if (!RWST_READ_WAIT(l, flags)) { 88 mutex_exit(&l->rwst_lock); 89 return (EINTR); 90 } 91 sleep_time += gethrtime(); 92 LOCKSTAT_RECORD4(LS_RW_ENTER_BLOCK, l, sleep_time, rw, 93 writer, readers); 94 } 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); 103 } 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; 112 } 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); 120 } 121 sleep_time += gethrtime(); 122 LOCKSTAT_RECORD4(LS_RW_ENTER_BLOCK, l, sleep_time, rw, 123 writer, readers); 124 } 125 RWST_WRITE_ENTER(l); 126 LOCKSTAT_RECORD(LS_RW_ENTER_ACQUIRE, l, rw); 127 } 128 mutex_exit(&l->rwst_lock); 129 return (flags & RWST_TRYENTER); 130 } 131 132 void 133 rwst_exit(rwstlock_t *l) 134 { 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); 143 } 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); 149 } 150 151 void 152 rwst_enter(rwstlock_t *l, krw_t rw) 153 { 154 (void) rwst_enter_common(l, rw, 0); 155 } 156 157 int 158 rwst_enter_sig(rwstlock_t *l, krw_t rw) 159 { 160 return (rwst_enter_common(l, rw, RWST_SIG)); 161 } 162 163 int 164 rwst_tryenter(rwstlock_t *l, krw_t rw) 165 { 166 return (rwst_enter_common(l, rw, RWST_TRYENTER)); 167 } 168 169 int 170 rwst_lock_held(rwstlock_t *l, krw_t rw) 171 { 172 if (rw != RW_WRITER) 173 return (RWST_READ_HELD(l)); 174 ASSERT(rw == RW_WRITER); 175 return (RWST_WRITE_OWNER(l)); 176 } 177 178 /*ARGSUSED*/ 179 void 180 rwst_init(rwstlock_t *l, char *name, krw_type_t krw_t, void *arg) 181 { 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); 186 } 187 188 void 189 rwst_destroy(rwstlock_t *l) 190 { 191 ASSERT(l->rwst_count == 0); 192 mutex_destroy(&l->rwst_lock); 193 cv_destroy(&l->rwst_rcv); 194 cv_destroy(&l->rwst_wcv); 195 } 196 197 struct _kthread * 198 rwst_owner(rwstlock_t *l) 199 { 200 return (RWST_OWNER(l)); 201 } 202