1 /* $OpenBSD: rwlock.h,v 1.11 2007/05/29 00:17:32 thib 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 const char *rwl_name; 77 }; 78 79 #define RWLOCK_INITIALIZER(name) { 0, name } 80 81 #define RWLOCK_WAIT 0x01UL 82 #define RWLOCK_WRWANT 0x02UL 83 #define RWLOCK_WRLOCK 0x04UL 84 #define RWLOCK_MASK 0x07UL 85 86 #define RWLOCK_OWNER(rwl) ((struct proc *)((rwl)->rwl_owner & ~RWLOCK_MASK)) 87 88 #define RWLOCK_READER_SHIFT 3UL 89 #define RWLOCK_READ_INCR (1UL << RWLOCK_READER_SHIFT) 90 91 void rw_init(struct rwlock *, const char *); 92 93 void rw_enter_read(struct rwlock *); 94 void rw_enter_write(struct rwlock *); 95 void rw_exit_read(struct rwlock *); 96 void rw_exit_write(struct rwlock *); 97 98 int rw_enter(struct rwlock *, int); 99 void rw_exit(struct rwlock *); 100 #define RW_WRITE 0x00UL /* exclusive lock */ 101 #define RW_READ 0x01UL /* shared lock */ 102 #define RW_DOWNGRADE 0x02UL /* downgrade exclusive to shared */ 103 #define RW_OPMASK 0x03UL 104 105 #define RW_INTR 0x10UL /* interruptible sleep */ 106 #define RW_SLEEPFAIL 0x20UL /* fail if we slept for the lock */ 107 #define RW_NOSLEEP 0x40UL /* don't wait for the lock */ 108 109 #ifndef rw_cas 110 int rw_cas(volatile unsigned long *, unsigned long, unsigned long); 111 #endif 112 113 #endif