1 /*	$NetBSD: rwlock.h,v 1.5 2014/12/10 04:38:00 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (C) 1998-2001, 2003  Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /* Id: rwlock.h,v 1.28 2007/06/19 23:47:18 tbox Exp  */
21 
22 #ifndef ISC_RWLOCK_H
23 #define ISC_RWLOCK_H 1
24 
25 /*! \file isc/rwlock.h */
26 
27 #include <isc/condition.h>
28 #include <isc/lang.h>
29 #include <isc/platform.h>
30 #include <isc/types.h>
31 
32 ISC_LANG_BEGINDECLS
33 
34 typedef enum {
35 	isc_rwlocktype_none = 0,
36 	isc_rwlocktype_read,
37 	isc_rwlocktype_write
38 } isc_rwlocktype_t;
39 
40 #ifdef ISC_PLATFORM_USETHREADS
41 #ifndef ISC_PLATFORM_USE_NATIVE_RWLOCKS
42 #if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
43 #define ISC_RWLOCK_USEATOMIC 1
44 #endif
45 
46 struct isc_rwlock {
47 	/* Unlocked. */
48 	unsigned int		magic;
49 	isc_mutex_t		lock;
50 
51 #if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
52 	/*
53 	 * When some atomic instructions with hardware assistance are
54 	 * available, rwlock will use those so that concurrent readers do not
55 	 * interfere with each other through mutex as long as no writers
56 	 * appear, massively reducing the lock overhead in the typical case.
57 	 *
58 	 * The basic algorithm of this approach is the "simple
59 	 * writer-preference lock" shown in the following URL:
60 	 * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/rw.html
61 	 * but our implementation does not rely on the spin lock unlike the
62 	 * original algorithm to be more portable as a user space application.
63 	 */
64 
65 	/* Read or modified atomically. */
66 	isc_int32_t		write_requests;
67 	isc_int32_t		write_completions;
68 	isc_int32_t		cnt_and_flag;
69 
70 	/* Locked by lock. */
71 	isc_condition_t		readable;
72 	isc_condition_t		writeable;
73 	unsigned int		readers_waiting;
74 
75 	/* Locked by rwlock itself. */
76 	unsigned int		write_granted;
77 
78 	/* Unlocked. */
79 	unsigned int		write_quota;
80 
81 #else  /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
82 
83 	/*%< Locked by lock. */
84 	isc_condition_t		readable;
85 	isc_condition_t		writeable;
86 	isc_rwlocktype_t	type;
87 
88 	/*% The number of threads that have the lock. */
89 	unsigned int		active;
90 
91 	/*%
92 	 * The number of lock grants made since the lock was last switched
93 	 * from reading to writing or vice versa; used in determining
94 	 * when the quota is reached and it is time to switch.
95 	 */
96 	unsigned int		granted;
97 
98 	unsigned int		readers_waiting;
99 	unsigned int		writers_waiting;
100 	unsigned int		read_quota;
101 	unsigned int		write_quota;
102 	isc_rwlocktype_t	original;
103 #endif  /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
104 };
105 #endif /* !ISC_PLATFORM_USE_NATIVE_RWLOCKS */
106 #else /* ISC_PLATFORM_USETHREADS */
107 struct isc_rwlock {
108 	unsigned int		magic;
109 	isc_rwlocktype_t	type;
110 	unsigned int		active;
111 };
112 #endif /* ISC_PLATFORM_USETHREADS */
113 
114 
115 isc_result_t
116 isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
117 		unsigned int write_quota);
118 
119 isc_result_t
120 isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
121 
122 isc_result_t
123 isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
124 
125 isc_result_t
126 isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
127 
128 isc_result_t
129 isc_rwlock_tryupgrade(isc_rwlock_t *rwl);
130 
131 void
132 isc_rwlock_downgrade(isc_rwlock_t *rwl);
133 
134 void
135 isc_rwlock_destroy(isc_rwlock_t *rwl);
136 
137 ISC_LANG_ENDDECLS
138 
139 #endif /* ISC_RWLOCK_H */
140