summaryrefslogtreecommitdiff
path: root/usr/src/lib/libnisdb/nisdb_rw.h
blob: 7d8bea9bacf5a1f4b2c5c60f2b4c599ecceabc4f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 2001 by Sun Microsystems, Inc.
 * All rights reserved.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#ifndef	_NISDB_RW_H
#define	_NISDB_RW_H

#include <pthread.h>
#include <thread.h>
#include <synch.h>
#include <stdlib.h>
#include <malloc.h>
#include <sys/errno.h>

#ifdef	__cplusplus
extern "C" {
#endif

#define	INV_PTHREAD_ID	0

/*
 * DEFAULTNISDBRWLOCK_RW is the default initializer that does _not_
 * force read lock requests to write locks, while DEFAULTNISDBRWLOCK_W
 * does force all locks to be exclusive.
 *
 * Locks should be initialized DEFAULTNISDBRWLOCK_W until it's been
 * determined that non-exclusive locking can be safely used; see
 * comments in __nisdb_rwinit() in nisdb_rw.c.
 */
#define	DEFAULTNISDBRWLOCK_RW	{DEFAULTMUTEX, DEFAULTCV, 0, 0, \
					0, {INV_PTHREAD_ID, 0, 0, 0}, \
					0, 0, {INV_PTHREAD_ID, 0, 0, 0}}

#define	DEFAULTNISDBRWLOCK_W	{DEFAULTMUTEX, DEFAULTCV, 0, 1, \
					0, {INV_PTHREAD_ID, 0, 0, 0}, \
					0, 0, {INV_PTHREAD_ID, 0, 0, 0}}

#define	DEFAULTNISDBRWLOCK	DEFAULTNISDBRWLOCK_W

/*
 * The value used for the 'force_write' field initialization in
 * __nisdb_rwinit(). Should be one unless it's been determined that
 * read locks can safely be used in for _all_ locks initialized
 * by __nisdb_rwinit().
 */
#define	NISDB_FORCE_WRITE	1

#ifdef	NISDB_MT_DEBUG

#define	DECLMUTEXLOCK(var)	pthread_mutex_t var ## _pmutex = \
					PTHREAD_MUTEX_INITIALIZER; \
				pthread_t var ## _owner = INV_PTHREAD_ID
#define	USEMUTEXLOCK(var)	extern pthread_mutex_t var ## _pmutex; \
				extern pthread_t var ## _owner
#define	STRUCTMUTEXLOCK(var)	pthread_mutex_t var ## _pmutex; \
				pthread_t var ## _owner
#define	INITMUTEX(var)		(void) pthread_mutex_init(&var ## _pmutex, 0)
#define	MUTEXLOCK(var, msg)	if (var ## _owner != pthread_self()) { \
					pthread_mutex_lock(&var ## _pmutex); \
					var ## _owner = pthread_self(); \
				} else \
					abort();
#define	MUTEXUNLOCK(var, msg)	if (var ## _owner == pthread_self()) { \
					var ## _owner = INV_PTHREAD_ID; \
					pthread_mutex_unlock(&var ## _pmutex);\
				} else \
					abort();
#define	ASSERTMUTEXHELD(var)	if (var ## _owner != pthread_self()) \
					abort();

#define	DECLRWLOCK(var)		__nisdb_rwlock_t var ## _rwlock = \
						DEFAULTNISDBRWLOCK
#define	USERWLOCK(var)		extern __nisdb_rwlock_t var ## _rwlock
#define	STRUCTRWLOCK(var)	__nisdb_rwlock_t var ## _rwlock
#define	INITRW(var)		(void) __nisdb_rwinit(&var ## _rwlock)
#define	READLOCKOK(var)		(void) __nisdb_rw_readlock_ok(&var ## _rwlock)
#define	RLOCK(var)		__nisdb_rlock(&var ## _rwlock)
#define	WLOCK(var)		__nisdb_wlock(&var ## _rwlock)
#define	TRYWLOCK(var)		__nisdb_wlock_trylock(&var ## _rwlock, 1)
#define	RULOCK(var)		__nisdb_rulock(&var ## _rwlock)
#define	WULOCK(var)		__nisdb_wulock(&var ## _rwlock)
#define	DESTROYRW(var)		__nisdb_destroy_lock(&var ## _rwlock)
#define	ASSERTWHELD(var)	if (__nisdb_assert_wheld(&var ## _rwlock) \
					!= 0) \
					abort();
#define	ASSERTRHELD(var)	if (__nisdb_assert_rheld(&var ## _rwlock) \
					!= 0) \
					abort();

#else	/* NISDB_MT_DEBUG */

#define	DECLMUTEXLOCK(var)	pthread_mutex_t var ## _pmutex = \
					PTHREAD_MUTEX_INITIALIZER
#define	USEMUTEXLOCK(var)	extern pthread_mutex_t var ## _pmutex
#define	STRUCTMUTEXLOCK(var)	pthread_mutex_t var ## _pmutex
#define	INITMUTEX(var)		(void) pthread_mutex_init(&var ## _pmutex, 0)
#define	MUTEXLOCK(var, msg)	pthread_mutex_lock(&var ## _pmutex)
#define	MUTEXUNLOCK(var, msg)	pthread_mutex_unlock(&var ## _pmutex)

#define	DECLRWLOCK(var)		__nisdb_rwlock_t var ## _rwlock = \
						DEFAULTNISDBRWLOCK
#define	USERWLOCK(var)		extern __nisdb_rwlock_t var ## _rwlock
#define	STRUCTRWLOCK(var)	__nisdb_rwlock_t var ## _rwlock
#define	INITRW(var)		(void) __nisdb_rwinit(&var ## _rwlock)
#define	READLOCKOK(var)		(void) __nisdb_rw_readlock_ok(&var ## _rwlock)
#define	RLOCK(var)		__nisdb_rlock(&var ## _rwlock)
#define	WLOCK(var)		__nisdb_wlock(&var ## _rwlock)
#define	TRYWLOCK(var)		__nisdb_wlock_trylock(&var ## _rwlock, 1)
#define	RULOCK(var)		__nisdb_rulock(&var ## _rwlock)
#define	WULOCK(var)		__nisdb_wulock(&var ## _rwlock)
#define	DESTROYRW(var)		__nisdb_destroy_lock(&var ## _rwlock)
#define	ASSERTMUTEXHELD(var)
#define	ASSERTWHELD(var)
#define	ASSERTRHELD(var)

#endif	/* NISDB_MT_DEBUG */

/* Nesting-safe RW locking */
typedef struct __nisdb_rwlock {
	pthread_t		id;	/* Which thread */
	uint32_t		count;	/* Lock depth for thread */
	uint32_t		wait;	/* Blocked on mutex */
	struct __nisdb_rwlock	*next;	/* Next reader record */
} __nisdb_rl_t;

typedef struct {
	mutex_t		mutex;		/* Exclusive access to structure */
	cond_t		cv;		/* CV for signaling */
	uint32_t	destroyed;	/* Set if lock has been destroyed */
	uint32_t	force_write;	/* Set if read locks forced to write */
	uint32_t	writer_count;	/* Number of writer threads [0, 1] */
	__nisdb_rl_t	writer;		/* Writer record */
	uint32_t	reader_count;	/* # of reader threads [0, N] */
	uint32_t	reader_blocked;	/* # of readers blocked on mutex */
	__nisdb_rl_t	reader;		/* List of reader records */
} __nisdb_rwlock_t;

extern int		__nisdb_rwinit(__nisdb_rwlock_t *);
extern int		__nisdb_rw_readlock_ok(__nisdb_rwlock_t *rw);
extern int		__nisdb_rw_force_writelock(__nisdb_rwlock_t *rw);
extern int		__nisdb_wlock(__nisdb_rwlock_t *);
extern int		__nisdb_wlock_trylock(__nisdb_rwlock_t *, int);
extern int		__nisdb_rlock(__nisdb_rwlock_t *);
extern int		__nisdb_wulock(__nisdb_rwlock_t *);
extern int		__nisdb_rulock(__nisdb_rwlock_t *);
extern int		__nisdb_assert_wheld(__nisdb_rwlock_t *);
extern int		__nisdb_assert_rheld(__nisdb_rwlock_t *);
extern int		__nisdb_destroy_lock(__nisdb_rwlock_t *);
extern void		__nisdb_lock_report(__nisdb_rwlock_t *rw);

#ifdef	__cplusplus
}
#endif

#endif	/* _NISDB_RW_H */