00001 // Copyright (C) 2001, Compaq Computer Corporation 00002 // 00003 // This file is part of Vesta. 00004 // 00005 // Vesta is free software; you can redistribute it and/or 00006 // modify it under the terms of the GNU Lesser General Public 00007 // License as published by the Free Software Foundation; either 00008 // version 2.1 of the License, or (at your option) any later version. 00009 // 00010 // Vesta is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 // Lesser General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU Lesser General Public 00016 // License along with Vesta; if not, write to the Free Software 00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00018 00019 // 00020 // ReadersWritersLock.H 00021 // 00022 // Readers/writers locks 00023 // 00024 #ifndef _RDWRLOCK 00025 #define _RDWRLOCK 1 00026 00027 #include <pthread.h> 00028 #include "Basics.H" 00029 00030 #ifdef PTHREAD_RWLOCK_INITIALIZER 00031 // #define USE_PTHREAD_RWLOCK 00032 #endif 00033 00034 #ifndef USE_PTHREAD_RWLOCK 00035 struct RWLock_Queue_Item; 00036 #endif 00037 00038 // If we're building an executable without assertions, we might as 00039 // well strip out the acquire/enqueue time. 00040 #if defined(NDEBUG) 00041 #define NO_ACQUIRE_DEBUG_DATA 00042 #endif 00043 00044 // Simple readers/writers locks. There can be either many readers, 00045 // one writer, or neither, but not both at once. 00046 00047 // If favorWriters is false, a new reader is granted the lock whenever 00048 // possible (that is, when the lock is not held, or when other readers 00049 // hold it). If favorWriters is true, a new reader is not granted the 00050 // lock if one or more writers are waiting to acquire it. 00051 00052 // Special features for repository: (1) mutex is static, (2) fields 00053 // are public and methods are virtual to allow subclasses to add or 00054 // override methods. 00055 00056 class ReadersWritersLock { 00057 private: 00058 #ifdef USE_PTHREAD_RWLOCK 00059 pthread_rwlock_t rwlock; 00060 00061 // Note: this member variable is only modified by a thread holding a 00062 // write lock. 00063 bool write_locked; 00064 00065 // Try to ensure that the readers/writers lock doesn't chare a cache 00066 // line with anything else. 00067 char pad[64]; 00068 00069 #else 00070 Basics::mutex mu; 00071 // Invariant: either readers == writers == 0, or 00072 // readers > 0 && writers == 0, or 00073 // readers == 0 && writers = 1 00074 int readers; 00075 int writers; 00076 00077 RWLock_Queue_Item *q_head, *q_tail; 00078 00079 #if !defined(NO_ACQUIRE_DEBUG_DATA) 00080 // Debug info: acquire_time and acquire_thread are set when it is 00081 // first locked for reading or writing. (When there are multiple 00082 // readers, only the first thread sets these.) This is sometimes 00083 // useful for post-motrem debugging. 00084 time_t acquire_time; 00085 pthread_t acquire_thread; 00086 #endif 00087 00088 #endif 00089 public: // normal public methods 00090 ReadersWritersLock(bool favorWriters) throw(); 00091 ~ReadersWritersLock() throw(); 00092 void acquireRead() throw(); 00093 void releaseRead() throw(); // assert(readers > 0); 00094 void acquireWrite() throw(); 00095 void releaseWrite() throw(); // assert(writers == 1); 00096 00097 // virtual void downgradeWriteToRead() throw(); // assert(writers == 1); 00098 00099 // If lock can be acquired immediately, do so and return true. 00100 // If there is a conflict, return false. 00101 bool tryRead() throw(); 00102 bool tryWrite() throw(); 00103 00104 // Assert (readers > 0) xor (writers == 1); 00105 // If writers == 1, releaseWrite and return true. 00106 // If readers > 0, releaseRead and return false. 00107 bool release() throw(); 00108 00109 // Assert (readers > 0) xor (writers == 1); 00110 // If writers == 1, downgradeWriteToRead and return true. 00111 // If readers > 0, return false. 00112 // virtual bool downgrade() throw(); 00113 }; 00114 #endif //_RDWRLOCK