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