00001 /* 00002 * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") 00003 * Copyright (C) 1998-2001, 2003 Internet Software Consortium. 00004 * 00005 * Permission to use, copy, modify, and/or distribute this software for any 00006 * purpose with or without fee is hereby granted, provided that the above 00007 * copyright notice and this permission notice appear in all copies. 00008 * 00009 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 00010 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 00011 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 00012 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 00013 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 00014 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 00015 * PERFORMANCE OF THIS SOFTWARE. 00016 */ 00017 00018 /* $Id: rwlock.h,v 1.28 2007/06/19 23:47:18 tbox Exp $ */ 00019 00020 #ifndef ISC_RWLOCK_H 00021 #define ISC_RWLOCK_H 1 00022 00023 /*! \file isc/rwlock.h */ 00024 00025 #include <isc/condition.h> 00026 #include <isc/lang.h> 00027 #include <isc/platform.h> 00028 #include <isc/types.h> 00029 00030 ISC_LANG_BEGINDECLS 00031 00032 typedef enum { 00033 isc_rwlocktype_none = 0, 00034 isc_rwlocktype_read, 00035 isc_rwlocktype_write 00036 } isc_rwlocktype_t; 00037 00038 #ifdef ISC_PLATFORM_USETHREADS 00039 #if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG) 00040 #define ISC_RWLOCK_USEATOMIC 1 00041 #endif 00042 00043 struct isc_rwlock { 00044 /* Unlocked. */ 00045 unsigned int magic; 00046 isc_mutex_t lock; 00047 00048 #if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG) 00049 /* 00050 * When some atomic instructions with hardware assistance are 00051 * available, rwlock will use those so that concurrent readers do not 00052 * interfere with each other through mutex as long as no writers 00053 * appear, massively reducing the lock overhead in the typical case. 00054 * 00055 * The basic algorithm of this approach is the "simple 00056 * writer-preference lock" shown in the following URL: 00057 * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/rw.html 00058 * but our implementation does not rely on the spin lock unlike the 00059 * original algorithm to be more portable as a user space application. 00060 */ 00061 00062 /* Read or modified atomically. */ 00063 isc_int32_t write_requests; 00064 isc_int32_t write_completions; 00065 isc_int32_t cnt_and_flag; 00066 00067 /* Locked by lock. */ 00068 isc_condition_t readable; 00069 isc_condition_t writeable; 00070 unsigned int readers_waiting; 00071 00072 /* Locked by rwlock itself. */ 00073 unsigned int write_granted; 00074 00075 /* Unlocked. */ 00076 unsigned int write_quota; 00077 00078 #else /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */ 00079 00080 /*%< Locked by lock. */ 00081 isc_condition_t readable; 00082 isc_condition_t writeable; 00083 isc_rwlocktype_t type; 00084 00085 /*% The number of threads that have the lock. */ 00086 unsigned int active; 00087 00088 /*% 00089 * The number of lock grants made since the lock was last switched 00090 * from reading to writing or vice versa; used in determining 00091 * when the quota is reached and it is time to switch. 00092 */ 00093 unsigned int granted; 00094 00095 unsigned int readers_waiting; 00096 unsigned int writers_waiting; 00097 unsigned int read_quota; 00098 unsigned int write_quota; 00099 isc_rwlocktype_t original; 00100 #endif /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */ 00101 }; 00102 #else /* ISC_PLATFORM_USETHREADS */ 00103 struct isc_rwlock { 00104 unsigned int magic; 00105 isc_rwlocktype_t type; 00106 unsigned int active; 00107 }; 00108 #endif /* ISC_PLATFORM_USETHREADS */ 00109 00110 00111 isc_result_t 00112 isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota, 00113 unsigned int write_quota); 00114 00115 isc_result_t 00116 isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type); 00117 00118 isc_result_t 00119 isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type); 00120 00121 isc_result_t 00122 isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type); 00123 00124 isc_result_t 00125 isc_rwlock_tryupgrade(isc_rwlock_t *rwl); 00126 00127 void 00128 isc_rwlock_downgrade(isc_rwlock_t *rwl); 00129 00130 void 00131 isc_rwlock_destroy(isc_rwlock_t *rwl); 00132 00133 ISC_LANG_ENDDECLS 00134 00135 #endif /* ISC_RWLOCK_H */