1 /* $OpenBSD: rwlock.h,v 1.3 2004/01/11 00:42:03 tedu Exp $ */ 2 /* 3 * Copyright (c) 2002 Artur Grabowski <art@openbsd.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 16 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 17 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 18 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 /* 28 * Multiple readers, single writer lock. 29 * 30 * Simplistic implementation modelled after rw locks in Solaris. 31 * 32 * The rwl_owner has the following layout: 33 * [ owner or count of readers | wrlock | wrwant | wait ] 34 * 35 * When the WAIT bit is set (bit 0), the lock has waiters sleeping on it. 36 * When the WRWANT bit is set (bit 1), at least one waiter wants a write lock. 37 * When the WRLOCK bit is set (bit 2) the lock is currently write-locked. 38 * 39 * When write locked, the upper bits contain the struct proc * pointer to 40 * the writer, otherwise they count the number of readers. 41 * 42 * We provide a simple machine independent implementation that can be 43 * optimized by machine dependent code when __HAVE_MD_RWLOCK is defined. 44 * 45 * MD code that defines __HAVE_MD_RWLOCK and implement four functions: 46 * 47 * void rw_enter_read(struct rwlock *) 48 * atomically test for RWLOCK_WRLOCK and if not set, increment the lock 49 * by RWLOCK_READ_INCR. While RWLOCK_WRLOCK is set, loop into rw_enter_wait. 50 * 51 * void rw_enter_write(struct rwlock *); 52 * atomically test for the lock being 0 (it's not possible to have 53 * owner/read count unset and waiter bits set) and if 0 set the owner to 54 * the proc and RWLOCK_WRLOCK. While not zero, loop into rw_enter_wait. 55 * 56 * void rw_exit_read(struct rwlock *); 57 * atomically decrement lock by RWLOCK_READ_INCR and unset RWLOCK_WAIT and 58 * RWLOCK_WRWANT remembering the old value of lock and if RWLOCK_WAIT was set, 59 * call rw_exit_waiters with the old contents of the lock. 60 * 61 * void rw_exit_write(struct rwlock *); 62 * atomically swap the contents of the lock with 0 and if RWLOCK_WAIT was 63 * set, call rw_exit_waiters with the old contents of the lock. 64 * 65 * (XXX - the rest of the API for this is not invented yet). 66 */ 67 68 #ifndef SYS_RWLOCK_H 69 #define SYS_RWLOCK_H 70 71 72 struct proc; 73 74 struct rwlock { 75 __volatile unsigned long rwl_owner; 76 }; 77 78 #define RWLOCK_INITIALIZER { 0 } 79 80 #define RWLOCK_WAIT 0x01 81 #define RWLOCK_WRWANT 0x02 82 #define RWLOCK_WRLOCK 0x04 83 #define RWLOCK_MASK 0x07 84 85 #define RWLOCK_OWNER(rwl) ((struct proc *)((rwl)->rwl_owner & ~RWLOCK_MASK)) 86 87 #define RWLOCK_READER_SHIFT 3 88 #define RWLOCK_READ_INCR (1 << RWLOCK_READER_SHIFT) 89 90 void rw_init(struct rwlock *); 91 92 void rw_enter_read(struct rwlock *); 93 void rw_enter_write(struct rwlock *); 94 void rw_exit_read(struct rwlock *); 95 void rw_exit_write(struct rwlock *); 96 97 /* 98 * Internal API. 99 */ 100 #define RW_WRITE 0x00 101 #define RW_READ 0x01 102 void rw_enter_wait(struct rwlock *, struct proc *, int); 103 void rw_exit_waiters(struct rwlock *, unsigned long); 104 105 #endif 106