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