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