1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7  *
8  * See the COPYRIGHT file distributed with this work for additional
9  * information regarding copyright ownership.
10  */
11 
12 #ifndef ISC_RWLOCK_H
13 #define ISC_RWLOCK_H 1
14 
15 #include <inttypes.h>
16 
17 /*! \file isc/rwlock.h */
18 
19 #include <isc/atomic.h>
20 #include <isc/condition.h>
21 #include <isc/lang.h>
22 #include <isc/types.h>
23 
24 ISC_LANG_BEGINDECLS
25 
26 typedef enum {
27 	isc_rwlocktype_none = 0,
28 	isc_rwlocktype_read,
29 	isc_rwlocktype_write
30 } isc_rwlocktype_t;
31 
32 #if USE_PTHREAD_RWLOCK
33 #include <pthread.h>
34 
35 struct isc_rwlock {
36 	pthread_rwlock_t rwlock;
37 	atomic_bool	 downgrade;
38 };
39 
40 #else /* USE_PTHREAD_RWLOCK */
41 
42 struct isc_rwlock {
43 	/* Unlocked. */
44 	unsigned int	    magic;
45 	isc_mutex_t	    lock;
46 	atomic_int_fast32_t spins;
47 
48 	/*
49 	 * When some atomic instructions with hardware assistance are
50 	 * available, rwlock will use those so that concurrent readers do not
51 	 * interfere with each other through mutex as long as no writers
52 	 * appear, massively reducing the lock overhead in the typical case.
53 	 *
54 	 * The basic algorithm of this approach is the "simple
55 	 * writer-preference lock" shown in the following URL:
56 	 * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/rw.html
57 	 * but our implementation does not rely on the spin lock unlike the
58 	 * original algorithm to be more portable as a user space application.
59 	 */
60 
61 	/* Read or modified atomically. */
62 	atomic_int_fast32_t write_requests;
63 	atomic_int_fast32_t write_completions;
64 	atomic_int_fast32_t cnt_and_flag;
65 
66 	/* Locked by lock. */
67 	isc_condition_t readable;
68 	isc_condition_t writeable;
69 	unsigned int	readers_waiting;
70 
71 	/* Locked by rwlock itself. */
72 	atomic_uint_fast32_t write_granted;
73 
74 	/* Unlocked. */
75 	unsigned int write_quota;
76 };
77 
78 #endif /* USE_PTHREAD_RWLOCK */
79 
80 void
81 isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
82 		unsigned int write_quota);
83 
84 isc_result_t
85 isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
86 
87 isc_result_t
88 isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
89 
90 isc_result_t
91 isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
92 
93 isc_result_t
94 isc_rwlock_tryupgrade(isc_rwlock_t *rwl);
95 
96 void
97 isc_rwlock_downgrade(isc_rwlock_t *rwl);
98 
99 void
100 isc_rwlock_destroy(isc_rwlock_t *rwl);
101 
102 ISC_LANG_ENDDECLS
103 
104 #endif /* ISC_RWLOCK_H */
105