00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifdef _WIN32
00018 #include <spl/configwin32.h>
00019 #else
00020 #include <spl/autoconf/config.h>
00021 #endif
00022
00023 #include <errno.h>
00024 #ifdef HAVE_UNISTD_H
00025 #include <unistd.h>
00026 #endif
00027 #ifdef HAVE_SYS_TIME_H
00028 #include <sys/time.h>
00029 #endif
00030 #ifdef HAVE_TIME_H
00031 #include <time.h>
00032 #endif
00033
00034 #include <spl/Environment.h>
00035 #include <spl/threading/Mutex.h>
00036 #include <spl/threading/Event.h>
00037 #include <spl/threading/RWLock.h>
00038 #include <spl/Exception.h>
00039 #include <spl/String.h>
00040
00041 Mutex::Mutex()
00042 {
00043 m_timeoutMs = INFINITE;
00044 initialized = false;
00045 Init();
00046 }
00047
00048 Mutex::Mutex(int timeoutMs)
00049 {
00050 m_timeoutMs = timeoutMs;
00051 initialized = false;
00052 Init();
00053 }
00054
00055 Mutex::~Mutex()
00056 {
00057 if (initialized)
00058 {
00059 #ifdef WIN32
00060 CloseHandle(mutex);
00061 #else
00062 pthread_mutex_destroy( &mutex );
00063 #endif
00064 }
00065 }
00066
00067 void Mutex::Init()
00068 {
00069 if (initialized)
00070 {
00071 throw new Exception("Mutex already initialized");
00072 }
00073 #ifdef WIN32
00074 mutex = CreateMutex(NULL,FALSE,NULL);
00075 if (mutex == NULL)
00076 {
00077 throw new IOException(Environment::LastErrorMessage());
00078 }
00079 #else
00080 int ret;
00081 if ( (ret = pthread_mutex_init( &mutex, NULL )) != 0 )
00082 {
00083 throw new IOException(Environment::LastErrorMessage());
00084 }
00085 #endif
00086 initialized = true;
00087 return;
00088 }
00089
00090 bool Mutex::Lock()
00091 {
00092 if (!initialized)
00093 {
00094 throw new Exception("Mutex not initialized");
00095 }
00096 #ifdef WIN32
00097 int timeout = m_timeoutMs == 0 ? INFINITE : m_timeoutMs;
00098 int ret;
00099 if ( ret = (WAIT_TIMEOUT == WaitForSingleObject(mutex, timeout)) )
00100 {
00101 return false;
00102 }
00103 if ( ret == WAIT_FAILED )
00104 {
00105 throw new IOException(Environment::LastErrorMessage());
00106 }
00107 return true;
00108 #else
00109 if ( 0 != m_timeoutMs )
00110 {
00111
00112 int ret = pthread_mutex_trylock( &mutex );
00113 if ( 0 != ret )
00114 {
00115 if ( EBUSY == ret )
00116 {
00117 sleep(m_timeoutMs/1000);
00118 ret = pthread_mutex_trylock( &mutex );
00119 }
00120 if ( EBUSY == ret )
00121 {
00122 return false;
00123 }
00124 if ( 0 != ret )
00125 {
00126 throw new IOException(Environment::LastErrorMessage());
00127 }
00128 return true;
00129 }
00130 }
00131 else
00132 {
00133 int ret = pthread_mutex_lock( &mutex );
00134 if ( 0 != ret )
00135 {
00136 if ( EINVAL == ret )
00137 {
00138 throw new IOException(Environment::LastErrorMessage());
00139 }
00140 else if ( 0 != ret )
00141 {
00142 throw new IOException(Environment::LastErrorMessage());
00143 }
00144 return true;
00145 }
00146 }
00147 return false;
00148 #endif
00149 }
00150
00151 void Mutex::Unlock()
00152 {
00153 if (!initialized)
00154 {
00155 throw new Exception("Mutex not initialized");
00156 }
00157 #ifdef _WIN32
00158 if (!ReleaseMutex(mutex))
00159 {
00160 throw new IOException(Environment::LastErrorMessage());
00161 }
00162 #else
00163 int ret;
00164 if ( 0 != (ret = pthread_mutex_unlock(&mutex)) )
00165 {
00166 if ( EPERM != ret )
00167 {
00168 throw new IOException(Environment::LastErrorMessage());
00169 }
00170 }
00171 #endif
00172 }
00173
00174 Event::Event()
00175 {
00176 #ifdef WIN32
00177 if ( NULL == (hevent = CreateEvent(NULL, 0, 0, NULL)) )
00178 {
00179 throw OutOfMemoryException();
00180 }
00181 #else
00182 int ret;
00183 if ( 0 != (ret = pthread_mutex_init( &mtx, NULL )) )
00184 {
00185 throw new IOException(Environment::LastErrorMessage());
00186 }
00187 if ( 0 != (ret = pthread_cond_init( &cond, NULL )) )
00188 {
00189 throw new IOException(Environment::LastErrorMessage());
00190 }
00191 #endif
00192 m_timeoutMs = INFINITE;
00193 }
00194
00195 Event::Event( int timeoutMs )
00196 {
00197 #ifdef WIN32
00198 if ( NULL == (hevent = CreateEvent(NULL, 0, 0, NULL)) )
00199 {
00200 throw OutOfMemoryException();
00201 }
00202 #else
00203 int ret = pthread_mutex_init( &mtx, NULL );
00204 if ( 0 != ret )
00205 {
00206 throw new IOException(Environment::LastErrorMessage());
00207 }
00208 if ( 0 != (ret = pthread_cond_init( &cond, NULL )) )
00209 {
00210 throw new IOException(Environment::LastErrorMessage());
00211 }
00212 #endif
00213 m_timeoutMs = timeoutMs;
00214 }
00215
00216 void Event::SetTimeOut( int ms )
00217 {
00218 m_timeoutMs = ms;
00219 }
00220
00221 Event::~Event()
00222 {
00223 #ifdef WIN32
00224 CloseHandle(hevent);
00225 #else
00226 pthread_mutex_destroy( &mtx );
00227 pthread_cond_destroy( &cond );
00228 #endif
00229 }
00230
00231 void Event::Wait()
00232 {
00233 #ifdef WIN32
00234 DWORD ret = WaitForSingleObject(hevent, m_timeoutMs);
00235 if (ret == WAIT_FAILED)
00236 {
00237 throw new IOException(Environment::LastErrorMessage());
00238 }
00239 #else
00240 int ret;
00241
00242 if ( 0 != (ret = pthread_mutex_lock(&mtx)) )
00243 {
00244 throw new IOException(Environment::LastErrorMessage());
00245 }
00246
00247 if ( 0 != m_timeoutMs )
00248 {
00249 struct timespec ts;
00250 struct timeval tp;
00251
00252 gettimeofday(&tp, NULL);
00253 ts.tv_sec = tp.tv_sec;
00254 ts.tv_nsec = tp.tv_usec * 1000;
00255 ts.tv_sec += m_timeoutMs / 1000;
00256
00257 ret = pthread_cond_timedwait(&cond, &mtx, &ts);
00258 }
00259 else
00260 {
00261 ret = pthread_cond_wait(&cond, &mtx);
00262 }
00263 if ( 0 != ret && ETIMEDOUT != ret )
00264 {
00265 throw new IOException(Environment::LastErrorMessage());
00266 }
00267 if ( 0 != (ret = pthread_mutex_unlock( &mtx )) )
00268 {
00269 throw new IOException(Environment::LastErrorMessage());
00270 }
00271
00272 #endif
00273 }
00274
00275 void Event::Notify()
00276 {
00277 #ifdef WIN32
00278 if (!SetEvent(hevent))
00279 {
00280 throw new IOException(Environment::LastErrorMessage());
00281 }
00282 #else
00283 if (0 != pthread_cond_signal(&cond))
00284 {
00285 throw new IOException(Environment::LastErrorMessage());
00286 }
00287 #endif
00288 }
00289
00290 RWLock::RWLock()
00291 #if defined(_WIN32) || defined(__TANDEM)
00292 : m_stateMtx(), m_readLockCount(0), m_writeLockCount(0), m_waitingWriters(5000), m_waitingWritersCount(0), m_waitingReaders(5000), m_waitingReadersCount(0)
00293 #endif
00294 {
00295 #if defined(_WIN32) || defined(__TANDEM)
00296 #else
00297 if ( 0 != pthread_rwlock_init(&m_rwlock, NULL) )
00298 {
00299 throw new IOException(Environment::LastErrorMessage());
00300 }
00301 #endif
00302 }
00303
00304 RWLock::~RWLock()
00305 {
00306 #if defined(_WIN32) || defined(__TANDEM)
00307 #else
00308 pthread_rwlock_destroy(&m_rwlock);
00309 #endif
00310 }
00311
00312 void RWLock::LockRead()
00313 {
00314 #if defined(_WIN32) || defined(__TANDEM)
00315 while ( true )
00316 {
00317 m_stateMtx.Lock();
00318 if ( m_waitingWritersCount > 0 || 0 != m_writeLockCount )
00319 {
00320 m_waitingReadersCount++;
00321 m_stateMtx.Unlock();
00322 m_waitingReaders.Wait();
00323 m_stateMtx.Lock();
00324 m_waitingReadersCount--;
00325 m_stateMtx.Unlock();
00326 }
00327 else
00328 {
00329 ASSERT(0 == m_writeLockCount);
00330 m_readLockCount++;
00331 m_stateMtx.Unlock();
00332 return;
00333 }
00334 }
00335 #else
00336 if ( 0 != pthread_rwlock_rdlock(&m_rwlock) )
00337 {
00338 throw new IOException(Environment::LastErrorMessage());
00339 }
00340 #endif
00341 }
00342
00343 void RWLock::LockWrite()
00344 {
00345 #if defined(_WIN32) || defined(__TANDEM)
00346 while ( true )
00347 {
00348 m_stateMtx.Lock();
00349 if ( 0 != m_writeLockCount || m_waitingWritersCount > 0 || m_readLockCount != 0 )
00350 {
00351 m_waitingWritersCount++;
00352 m_stateMtx.Unlock();
00353 m_waitingWriters.Wait();
00354 m_stateMtx.Lock();
00355 m_waitingWritersCount--;
00356 m_stateMtx.Unlock();
00357 }
00358 else
00359 {
00360 ASSERT(0 == m_writeLockCount);
00361 m_writeLockCount++;
00362 m_stateMtx.Unlock();
00363 return;
00364 }
00365 }
00366 #else
00367 if ( 0 != pthread_rwlock_wrlock(&m_rwlock) )
00368 {
00369 throw new IOException(Environment::LastErrorMessage());
00370 }
00371 #endif
00372 }
00373
00374 void RWLock::UnlockRead()
00375 {
00376 #if defined(_WIN32) || defined(__TANDEM)
00377 m_stateMtx.Lock();
00378 m_readLockCount--;
00379 ASSERT(m_readLockCount >= 0);
00380 ASSERT( 0 == m_writeLockCount );
00381 m_stateMtx.Unlock();
00382
00383 if (0 == m_readLockCount && 0 != m_waitingWritersCount )
00384 {
00385 m_waitingWriters.Notify();
00386 }
00387 #else
00388 if (0 != pthread_rwlock_unlock(&m_rwlock))
00389 {
00390 throw new IOException(Environment::LastErrorMessage());
00391 }
00392 #endif
00393 }
00394
00395 void RWLock::UnlockWrite()
00396 {
00397 #if defined(_WIN32) || defined(__TANDEM)
00398 ASSERT( 0 == m_readLockCount );
00399
00400 m_stateMtx.Lock();
00401 ASSERT(m_writeLockCount == 1);
00402 m_writeLockCount--;
00403 if ( 0 != m_waitingWritersCount )
00404 {
00405 m_waitingWriters.Notify();
00406 }
00407 else if( 0 != m_waitingReadersCount )
00408 {
00409 m_waitingReaders.Notify();
00410 }
00411 m_stateMtx.Unlock();
00412 #else
00413 if (0 != pthread_rwlock_unlock(&m_rwlock))
00414 {
00415 throw new IOException(Environment::LastErrorMessage());
00416 }
00417 #endif
00418 }