xref: /illumos-gate/usr/src/lib/libnisdb/nisdb_rw.h (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
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 (c) 2001 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #ifndef	_NISDB_RW_H
28 #define	_NISDB_RW_H
29 
30 #include <pthread.h>
31 #include <thread.h>
32 #include <synch.h>
33 #include <stdlib.h>
34 #include <malloc.h>
35 #include <sys/errno.h>
36 
37 #ifdef	__cplusplus
38 extern "C" {
39 #endif
40 
41 #define	INV_PTHREAD_ID	0
42 
43 /*
44  * DEFAULTNISDBRWLOCK_RW is the default initializer that does _not_
45  * force read lock requests to write locks, while DEFAULTNISDBRWLOCK_W
46  * does force all locks to be exclusive.
47  *
48  * Locks should be initialized DEFAULTNISDBRWLOCK_W until it's been
49  * determined that non-exclusive locking can be safely used; see
50  * comments in __nisdb_rwinit() in nisdb_rw.c.
51  */
52 #define	DEFAULTNISDBRWLOCK_RW	{DEFAULTMUTEX, DEFAULTCV, 0, 0, \
53 					0, {INV_PTHREAD_ID, 0, 0, 0}, \
54 					0, 0, {INV_PTHREAD_ID, 0, 0, 0}}
55 
56 #define	DEFAULTNISDBRWLOCK_W	{DEFAULTMUTEX, DEFAULTCV, 0, 1, \
57 					0, {INV_PTHREAD_ID, 0, 0, 0}, \
58 					0, 0, {INV_PTHREAD_ID, 0, 0, 0}}
59 
60 #define	DEFAULTNISDBRWLOCK	DEFAULTNISDBRWLOCK_W
61 
62 /*
63  * The value used for the 'force_write' field initialization in
64  * __nisdb_rwinit(). Should be one unless it's been determined that
65  * read locks can safely be used in for _all_ locks initialized
66  * by __nisdb_rwinit().
67  */
68 #define	NISDB_FORCE_WRITE	1
69 
70 #ifdef	NISDB_MT_DEBUG
71 
72 #define	DECLMUTEXLOCK(var)	pthread_mutex_t var ## _pmutex = \
73 					PTHREAD_MUTEX_INITIALIZER; \
74 				pthread_t var ## _owner = INV_PTHREAD_ID
75 #define	USEMUTEXLOCK(var)	extern pthread_mutex_t var ## _pmutex; \
76 				extern pthread_t var ## _owner
77 #define	STRUCTMUTEXLOCK(var)	pthread_mutex_t var ## _pmutex; \
78 				pthread_t var ## _owner
79 #define	INITMUTEX(var)		(void) pthread_mutex_init(&var ## _pmutex, 0)
80 #define	MUTEXLOCK(var, msg)	if (var ## _owner != pthread_self()) { \
81 					pthread_mutex_lock(&var ## _pmutex); \
82 					var ## _owner = pthread_self(); \
83 				} else \
84 					abort();
85 #define	MUTEXUNLOCK(var, msg)	if (var ## _owner == pthread_self()) { \
86 					var ## _owner = INV_PTHREAD_ID; \
87 					pthread_mutex_unlock(&var ## _pmutex);\
88 				} else \
89 					abort();
90 #define	ASSERTMUTEXHELD(var)	if (var ## _owner != pthread_self()) \
91 					abort();
92 
93 #define	DECLRWLOCK(var)		__nisdb_rwlock_t var ## _rwlock = \
94 						DEFAULTNISDBRWLOCK
95 #define	USERWLOCK(var)		extern __nisdb_rwlock_t var ## _rwlock
96 #define	STRUCTRWLOCK(var)	__nisdb_rwlock_t var ## _rwlock
97 #define	INITRW(var)		(void) __nisdb_rwinit(&var ## _rwlock)
98 #define	READLOCKOK(var)		(void) __nisdb_rw_readlock_ok(&var ## _rwlock)
99 #define	RLOCK(var)		__nisdb_rlock(&var ## _rwlock)
100 #define	WLOCK(var)		__nisdb_wlock(&var ## _rwlock)
101 #define	TRYWLOCK(var)		__nisdb_wlock_trylock(&var ## _rwlock, 1)
102 #define	RULOCK(var)		__nisdb_rulock(&var ## _rwlock)
103 #define	WULOCK(var)		__nisdb_wulock(&var ## _rwlock)
104 #define	DESTROYRW(var)		__nisdb_destroy_lock(&var ## _rwlock)
105 #define	ASSERTWHELD(var)	if (__nisdb_assert_wheld(&var ## _rwlock) \
106 					!= 0) \
107 					abort();
108 #define	ASSERTRHELD(var)	if (__nisdb_assert_rheld(&var ## _rwlock) \
109 					!= 0) \
110 					abort();
111 
112 #else	/* NISDB_MT_DEBUG */
113 
114 #define	DECLMUTEXLOCK(var)	pthread_mutex_t var ## _pmutex = \
115 					PTHREAD_MUTEX_INITIALIZER
116 #define	USEMUTEXLOCK(var)	extern pthread_mutex_t var ## _pmutex
117 #define	STRUCTMUTEXLOCK(var)	pthread_mutex_t var ## _pmutex
118 #define	INITMUTEX(var)		(void) pthread_mutex_init(&var ## _pmutex, 0)
119 #define	MUTEXLOCK(var, msg)	pthread_mutex_lock(&var ## _pmutex)
120 #define	MUTEXUNLOCK(var, msg)	pthread_mutex_unlock(&var ## _pmutex)
121 
122 #define	DECLRWLOCK(var)		__nisdb_rwlock_t var ## _rwlock = \
123 						DEFAULTNISDBRWLOCK
124 #define	USERWLOCK(var)		extern __nisdb_rwlock_t var ## _rwlock
125 #define	STRUCTRWLOCK(var)	__nisdb_rwlock_t var ## _rwlock
126 #define	INITRW(var)		(void) __nisdb_rwinit(&var ## _rwlock)
127 #define	READLOCKOK(var)		(void) __nisdb_rw_readlock_ok(&var ## _rwlock)
128 #define	RLOCK(var)		__nisdb_rlock(&var ## _rwlock)
129 #define	WLOCK(var)		__nisdb_wlock(&var ## _rwlock)
130 #define	TRYWLOCK(var)		__nisdb_wlock_trylock(&var ## _rwlock, 1)
131 #define	RULOCK(var)		__nisdb_rulock(&var ## _rwlock)
132 #define	WULOCK(var)		__nisdb_wulock(&var ## _rwlock)
133 #define	DESTROYRW(var)		__nisdb_destroy_lock(&var ## _rwlock)
134 #define	ASSERTMUTEXHELD(var)
135 #define	ASSERTWHELD(var)
136 #define	ASSERTRHELD(var)
137 
138 #endif	/* NISDB_MT_DEBUG */
139 
140 /* Nesting-safe RW locking */
141 typedef struct __nisdb_rwlock {
142 	pthread_t		id;	/* Which thread */
143 	uint32_t		count;	/* Lock depth for thread */
144 	uint32_t		wait;	/* Blocked on mutex */
145 	struct __nisdb_rwlock	*next;	/* Next reader record */
146 } __nisdb_rl_t;
147 
148 typedef struct {
149 	mutex_t		mutex;		/* Exclusive access to structure */
150 	cond_t		cv;		/* CV for signaling */
151 	uint32_t	destroyed;	/* Set if lock has been destroyed */
152 	uint32_t	force_write;	/* Set if read locks forced to write */
153 	uint32_t	writer_count;	/* Number of writer threads [0, 1] */
154 	__nisdb_rl_t	writer;		/* Writer record */
155 	uint32_t	reader_count;	/* # of reader threads [0, N] */
156 	uint32_t	reader_blocked;	/* # of readers blocked on mutex */
157 	__nisdb_rl_t	reader;		/* List of reader records */
158 } __nisdb_rwlock_t;
159 
160 extern int		__nisdb_rwinit(__nisdb_rwlock_t *);
161 extern int		__nisdb_rw_readlock_ok(__nisdb_rwlock_t *rw);
162 extern int		__nisdb_rw_force_writelock(__nisdb_rwlock_t *rw);
163 extern int		__nisdb_wlock(__nisdb_rwlock_t *);
164 extern int		__nisdb_wlock_trylock(__nisdb_rwlock_t *, int);
165 extern int		__nisdb_rlock(__nisdb_rwlock_t *);
166 extern int		__nisdb_wulock(__nisdb_rwlock_t *);
167 extern int		__nisdb_rulock(__nisdb_rwlock_t *);
168 extern int		__nisdb_assert_wheld(__nisdb_rwlock_t *);
169 extern int		__nisdb_assert_rheld(__nisdb_rwlock_t *);
170 extern int		__nisdb_destroy_lock(__nisdb_rwlock_t *);
171 extern void		__nisdb_lock_report(__nisdb_rwlock_t *rw);
172 
173 #ifdef	__cplusplus
174 }
175 #endif
176 
177 #endif	/* _NISDB_RW_H */
178