00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "MicoleBusWriteLock.h"
00025
00026 #ifdef _DEBUG
00027 #define new DEBUG_NEW
00028 #undef THIS_FILE
00029 static char THIS_FILE[] = __FILE__;
00030 #endif
00031
00032 inline bool Wait( int nObjects, HANDLE* pObjects, DWORD Timeout )
00033 {
00034 DWORD Result = WaitForMultipleObjects(nObjects, pObjects, true, Timeout);
00035 if ( DWORD(Result - WAIT_OBJECT_0) < nObjects )
00036 return true;
00037
00038
00039 return false;
00040 };
00041
00042 inline bool Wait1( HANDLE hObj, DWORD Timeout )
00043 {
00044 DWORD Result = WaitForSingleObject(hObj, Timeout);
00045 return (Result == WAIT_OBJECT_0);
00046 };
00047
00048 inline bool Wait2( HANDLE hObj1, HANDLE hObj2, DWORD Timeout )
00049 {
00050 HANDLE hArray[2] = {hObj1, hObj2};
00051 return Wait(2, hArray, Timeout);
00052 };
00053
00054 inline bool Wait3( HANDLE hObj1, HANDLE hObj2, HANDLE hObj3, DWORD Timeout )
00055 {
00056 HANDLE hArray[3] = {hObj1, hObj2, hObj3};
00057 return Wait(3, hArray, Timeout);
00058 };
00059
00060 MicoleBusReadWriteLock::MicoleBusReadWriteLock()
00061 :
00062 m_CanRead(true, true),
00063 m_CanWrite(true, true),
00064 m_Readers(0)
00065 {
00066 };
00067
00068 bool MicoleBusReadWriteLock::LockRead( DWORD Timeout )
00069 {
00070 if (!Wait2( m_Access, m_CanRead, Timeout))
00071 return false;
00072
00073 ++m_Readers;
00074 ResetEvent(m_CanWrite);
00075 ReleaseMutex(m_Access);
00076 return true;
00077 };
00078
00079 bool MicoleBusReadWriteLock::UnlockRead( DWORD Timeout )
00080 {
00081 if (!Wait1( m_Access, Timeout ))
00082 return false;
00083
00084
00085 ASSERT(m_Readers > 0);
00086 --m_Readers;
00087
00088 if (m_Readers == 0)
00089 {
00090 SetEvent(m_CanWrite);
00091 };
00092
00093 ReleaseMutex(m_Access);
00094 return true;
00095 };
00096
00097 bool MicoleBusReadWriteLock::LockWrite( DWORD Timeout )
00098 {
00099 if (!Wait3(m_Access, m_CanWrite, m_WriterMutex, Timeout))
00100 return false;
00101
00102 ASSERT(m_Readers == 0);
00103 ResetEvent(m_CanRead);
00104 ReleaseMutex(m_Access);
00105
00106
00107 return true;
00108 };
00109
00110 bool MicoleBusReadWriteLock::UnlockWrite( DWORD Timeout )
00111 {
00112 if (!Wait1( m_Access, Timeout ))
00113 return false;
00114
00115 ASSERT(m_Readers == 0);
00116
00117 ReleaseMutex(m_WriterMutex);
00118 SetEvent(m_CanWrite);
00119 SetEvent(m_CanRead);
00120 ReleaseMutex(m_Access);
00121 return true;
00122 };
00123
00124
00125 MicoleBusReadWriteLockEx::MicoleBusReadWriteLockEx()
00126 :
00127 m_CanRead(true, true),
00128 m_CanWrite(true, true),
00129 m_TotalReaderThreads(0),
00130 m_TotalWriterThreads(0)
00131 {
00132 };
00133
00134 bool MicoleBusReadWriteLockEx::LockRead( DWORD Timeout )
00135 {
00136 DWORD ThreadId = GetCurrentThreadId();
00137
00138
00139 if (!Wait1( m_Access, Timeout ))
00140 return false;
00141
00142 KThreadMap::iterator pInfo = m_Threads.find(ThreadId);
00143
00144 if (pInfo != m_Threads.end())
00145 {
00146
00147 KThreadInfo& Info = pInfo->second;
00148 ASSERT( Info.IsReader() || Info.IsWriter() );
00149 ++Info.ReadCount;
00150 }
00151 else
00152 {
00153
00154 ReleaseMutex(m_Access);
00155
00156 if (!Wait2(m_Access, m_CanRead, Timeout))
00157 return false;
00158
00159 KThreadInfo Info;
00160 Info.ReadCount = 1;
00161 Info.WriteCount = 0;
00162 m_Threads[ThreadId] = Info;
00163 IncReaders();
00164 }
00165
00166 ReleaseMutex(m_Access);
00167
00168 return true;
00169 };
00170
00171 bool MicoleBusReadWriteLockEx::UnlockRead( DWORD Timeout )
00172 {
00173 DWORD ThreadId = GetCurrentThreadId();
00174
00175
00176 if (!Wait1( m_Access, Timeout ))
00177 return false;
00178
00179 KThreadMap::iterator pInfo = m_Threads.find(ThreadId);
00180
00181
00182 ASSERT(pInfo != m_Threads.end());
00183
00184 KThreadInfo& Info = pInfo->second;
00185 ASSERT(Info.IsReader());
00186
00187 --Info.ReadCount;
00188 if (!Info.IsWriter() && !Info.IsReader())
00189 {
00190 DecReaders();
00191 m_Threads.erase(pInfo);
00192 }
00193
00194 ReleaseMutex(m_Access);
00195 return true;
00196 };
00197
00198 bool MicoleBusReadWriteLockEx::LockWrite( DWORD Timeout )
00199 {
00200 DWORD ThreadId = GetCurrentThreadId();
00201
00202
00203 if (!Wait1( m_Access, Timeout ))
00204 return false;
00205
00206 KThreadMap::iterator pInfo = m_Threads.find(ThreadId);
00207
00208 if (pInfo != m_Threads.end())
00209 {
00210
00211 KThreadInfo& Info = pInfo->second;
00212 ASSERT( Info.IsReader() || Info.IsWriter() );
00213
00214 if (!Info.IsWriter())
00215 {
00216 ASSERT(Info.IsReader());
00217
00218
00219
00220 VERIFY( Wait1(m_WriterMutex, 0 ) );
00221
00222
00223 DecReaders();
00224
00225
00226
00227
00228 IncWriters();
00229
00230 if (m_TotalReaderThreads != 0)
00231 {
00232
00233
00234
00235
00236 ReleaseMutex(m_Access);
00237 if (!Wait2( m_Access, m_CanWrite, Timeout ))
00238 {
00239
00240 VERIFY( Wait1(m_Access, INFINITE) );
00241
00242
00243 IncReaders();
00244
00245
00246 DecWriters();
00247
00248 ReleaseMutex(m_WriterMutex);
00249 ReleaseMutex(m_Access);
00250 return false;
00251 }
00252 }
00253 }
00254 }
00255 else
00256 {
00257
00258
00259
00260
00261 IncWriters();
00262
00263
00264 ReleaseMutex(m_Access);
00265
00266 if (!Wait3(m_Access, m_CanWrite, m_WriterMutex, Timeout))
00267 {
00268
00269 VERIFY( Wait1(m_Access, INFINITE) );
00270 DecWriters();
00271 ReleaseMutex(m_Access);
00272 return false;
00273 }
00274
00275 KThreadInfo Info;
00276 Info.ReadCount = 0;
00277 Info.WriteCount = 0;
00278
00279 std::pair<KThreadMap::iterator, bool> InsertResult =
00280 m_Threads.insert(std::make_pair(ThreadId, Info));
00281
00282 ASSERT(InsertResult.second);
00283 pInfo = InsertResult.first;
00284
00285
00286 }
00287
00288
00289 ++pInfo->second.WriteCount;
00290 ReleaseMutex(m_Access);
00291 return true;
00292 };
00293
00294 bool MicoleBusReadWriteLockEx::UnlockWrite( DWORD Timeout )
00295 {
00296 DWORD ThreadId = GetCurrentThreadId();
00297
00298
00299 if (!Wait1( m_Access, Timeout ))
00300 return false;
00301
00302
00303 KThreadMap::iterator pInfo = m_Threads.find(ThreadId);
00304 ASSERT(pInfo != m_Threads.end());
00305
00306 KThreadInfo& Info = pInfo->second;
00307 ASSERT(Info.IsWriter());
00308
00309 --Info.WriteCount;
00310 if (!Info.IsWriter())
00311 {
00312
00313 ReleaseMutex(m_WriterMutex);
00314 DecWriters();
00315
00316 if (Info.IsReader())
00317 {
00318
00319 IncReaders();
00320 }
00321 else
00322 {
00323
00324 m_Threads.erase(pInfo);
00325 }
00326 }
00327
00328 ReleaseMutex(m_Access);
00329 return true;
00330 };
00331