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