00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00038 #include "blocxx/BLOCXX_config.h"
00039 #include "blocxx/RWLocker.hpp"
00040 #include "blocxx/Assertion.hpp"
00041 #include "blocxx/ThreadImpl.hpp"
00042 #include "blocxx/TimeoutException.hpp"
00043 #include "blocxx/ExceptionIds.hpp"
00044
00045 namespace BLOCXX_NAMESPACE
00046 {
00047
00048 BLOCXX_DEFINE_EXCEPTION_WITH_ID(RWLocker);
00050 RWLocker::RWLocker()
00051 : m_waiting_writers()
00052 , m_waiting_readers()
00053 , m_num_waiting_writers(0)
00054 , m_num_waiting_readers(0)
00055 , m_readers_next(0)
00056 , m_guard()
00057 , m_state(0)
00058 {
00059 }
00061 RWLocker::~RWLocker()
00062 {
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072 }
00074 void
00075 RWLocker::getReadLock(UInt32 sTimeout, UInt32 usTimeout)
00076 {
00077 NonRecursiveMutexLock l(m_guard);
00078
00079
00080
00081
00082
00083
00084 Thread_t tid = ThreadImpl::currentThread();
00085 if (m_state < 0)
00086 {
00087
00088 if (ThreadImpl::sameThreads(m_writer, tid))
00089 {
00090 BLOCXX_THROW(DeadlockException, "A thread that has a write lock is trying to acquire a read lock.");
00091 }
00092 }
00093 while (m_state < 0)
00094 {
00095 ++m_num_waiting_readers;
00096
00097 if (!m_waiting_readers.timedWait(l, sTimeout, usTimeout))
00098 {
00099 --m_num_waiting_readers;
00100 BLOCXX_THROW(TimeoutException, "Timeout while waiting for read lock.");
00101 }
00102 --m_num_waiting_readers;
00103 }
00104
00105
00106 m_state++;
00107 m_readers.push_back(tid);
00108 }
00110 void
00111 RWLocker::getWriteLock(UInt32 sTimeout, UInt32 usTimeout)
00112 {
00113 NonRecursiveMutexLock l(m_guard);
00114
00115
00116
00117
00118
00119 Thread_t tid = ThreadImpl::currentThread();
00120 if (m_state != 0)
00121 {
00122
00123 for (size_t i = 0; i < m_readers.size(); ++i)
00124 {
00125 if (ThreadImpl::sameThreads(m_readers[i], tid))
00126 {
00127 BLOCXX_THROW(DeadlockException, "A thread that has a read lock is trying to acquire a write lock.");
00128 }
00129 }
00130 }
00131 while (m_state != 0)
00132 {
00133 ++m_num_waiting_writers;
00134 if (!m_waiting_writers.timedWait(l, sTimeout, usTimeout))
00135 {
00136 --m_num_waiting_writers;
00137 BLOCXX_THROW(TimeoutException, "Timeout while waiting for write lock.");
00138 }
00139 --m_num_waiting_writers;
00140 }
00141 m_state = -1;
00142 m_writer = tid;
00143 }
00145 void
00146 RWLocker::releaseReadLock()
00147 {
00148 NonRecursiveMutexLock l(m_guard);
00149 if (m_state > 0)
00150 --m_state;
00151 else
00152 BLOCXX_THROW(RWLockerException, "A writer is releasing a read lock");
00153 if (m_state == 0)
00154 {
00155 doWakeups();
00156 }
00157 Thread_t tid = ThreadImpl::currentThread();
00158 size_t i = 0;
00159 while (i < m_readers.size())
00160 {
00161 if (ThreadImpl::sameThreads(m_readers[i], tid))
00162 {
00163 m_readers.remove(i);
00164 }
00165 else
00166 {
00167 ++i;
00168 }
00169 }
00170 }
00172 void
00173 RWLocker::releaseWriteLock()
00174 {
00175 NonRecursiveMutexLock l(m_guard);
00176 if (m_state == -1)
00177 {
00178 m_state = 0;
00179 }
00180 else
00181 {
00182 BLOCXX_THROW(RWLockerException, "A reader is releasing a write lock");
00183 }
00184
00185
00186 doWakeups();
00187 }
00189 void
00190 RWLocker::doWakeups()
00191 {
00192 if ( m_num_waiting_writers > 0 &&
00193 m_num_waiting_readers > 0)
00194 {
00195 if (m_readers_next == 1)
00196 {
00197 m_readers_next = 0;
00198 m_waiting_readers.notifyAll();
00199 }
00200 else
00201 {
00202 m_waiting_writers.notifyOne();
00203 m_readers_next = 1;
00204 }
00205 }
00206 else if (m_num_waiting_writers > 0)
00207 {
00208
00209 m_waiting_writers.notifyOne();
00210 }
00211 else if (m_num_waiting_readers > 0)
00212 {
00213
00214 m_waiting_readers.notifyAll();
00215 }
00216 }
00217
00218 }
00219