/* * * C++ Portable Types Library (PTypes) * Version 2.1.1 Released 27-Jun-2007 * * Copyright (C) 2001-2007 Hovik Melikyan * * http://www.melikyan.com/ptypes/ * */ #ifdef WIN32 # include #else # include #endif #include "pasync.h" PTYPES_BEGIN static void rwlock_fail() { fatal(CRIT_FIRST + 41, "rwlock failed"); } inline void rwlock_syscheck(int r) { if (r != 0) rwlock_fail(); } #ifdef __PTYPES_RWLOCK__ # ifdef WIN32 // // this implementation of the read/write lock is derived // from Apache Portable Runtime (APR) source, which // in turn was originally based on an erroneous (or just // incomplete?) example in one of the MSDN technical articles. // rwlock::rwlock() : mutex(), readcnt(-1), writecnt(0) { reading = CreateEvent(0, true, false, 0); finished = CreateEvent(0, false, true, 0); if (reading == 0 || finished == 0) rwlock_fail(); } rwlock::~rwlock() { CloseHandle(reading); CloseHandle(finished); } void rwlock::rdlock() { if (pincrement(&readcnt) == 0) { WaitForSingleObject(finished, INFINITE); SetEvent(reading); } WaitForSingleObject(reading, INFINITE); } void rwlock::wrlock() { mutex::enter(); WaitForSingleObject(finished, INFINITE); writecnt++; } void rwlock::unlock() { if (writecnt != 0) { writecnt--; SetEvent(finished); mutex::leave(); } else if (pdecrement(&readcnt) < 0) { ResetEvent(reading); SetEvent(finished); } } # else // !defined(WIN32) // // for other platforms that lack POSIX rwlock we implement // the rwlock object using POSIX condvar. the code below // is based on Sean Burke's algorithm posted in // comp.programming.threads. // rwlock::rwlock() : locks(0), writers(0), readers(0) { rwlock_syscheck(pthread_mutex_init(&mtx, 0)); rwlock_syscheck(pthread_cond_init(&readcond, 0)); rwlock_syscheck(pthread_cond_init(&writecond, 0)); } rwlock::~rwlock() { pthread_cond_destroy(&writecond); pthread_cond_destroy(&readcond); pthread_mutex_destroy(&mtx); } void rwlock::rdlock() { pthread_mutex_lock(&mtx); readers++; while (locks < 0) pthread_cond_wait(&readcond, &mtx); readers--; locks++; pthread_mutex_unlock(&mtx); } void rwlock::wrlock() { pthread_mutex_lock(&mtx); writers++; while (locks != 0) pthread_cond_wait(&writecond, &mtx); locks = -1; writers--; pthread_mutex_unlock(&mtx); } void rwlock::unlock() { pthread_mutex_lock(&mtx); if (locks > 0) { locks--; if (locks == 0) pthread_cond_signal(&writecond); } else { locks = 0; if (readers != 0) pthread_cond_broadcast(&readcond); else pthread_cond_signal(&writecond); } pthread_mutex_unlock(&mtx); } # endif // !defined(WIN32) #else // !defined(__PTYPES_RWLOCK__) // // for other systems we declare a fully-inlined rwlock // object in pasync.h // rwlock::rwlock() { rwlock_syscheck(pthread_rwlock_init(&rw, 0)); } #endif PTYPES_END