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