#include <pthread.h>
#include "dyldLock.h"
#define REAL_READER_WRITER_LOCK 0
class RecursiveReaderWriterLock
{
public:
RecursiveReaderWriterLock() __attribute__((visibility("hidden")));
void initIfNeeded();
void lockForSingleWritingThread() __attribute__((visibility("hidden")));
void unlockForSingleWritingThread() __attribute__((visibility("hidden")));
void lockForMultipleReadingThreads() __attribute__((visibility("hidden")));
void unlockForMultipleReadingThreads() __attribute__((visibility("hidden")));
private:
#if REAL_READER_WRITER_LOCK
struct ThreadRecursionCount {
pthread_t fThread;
uint32_t fCount;
};
bool writerThreadIsAnyThreadBut(pthread_t thread);
void writerThreadRetain(pthread_t thread);
bool writerThreadRelease(pthread_t thread);
enum { kMaxReaderThreads = 4 };
bool readerThreadSetRetain(pthread_t thread);
bool readerThreadSetRelease(pthread_t thread);
bool readerThreadSetContainsAnotherThread(pthread_t thread);
ThreadRecursionCount fWriterThread;
ThreadRecursionCount fReaderThreads[kMaxReaderThreads];
pthread_cond_t fLockFree;
pthread_mutex_t fMutex;
#else
pthread_mutex_t fMutex;
#endif
bool fInitialized; };
void RecursiveReaderWriterLock::initIfNeeded()
{
if ( ! fInitialized ) {
pthread_mutexattr_t recursiveMutexAttr;
pthread_mutexattr_init(&recursiveMutexAttr);
pthread_mutexattr_settype(&recursiveMutexAttr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&fMutex, &recursiveMutexAttr);
#if REAL_READER_WRITER_LOCK
pthread_cond_init(&fLockFree, NULL);
fWriterThread.fThread = NULL;
fWriterThread.fCount = 0;
for (int i=0; i < kMaxReaderThreads; ++i) {
fReaderThreads[i].fThread = NULL;
fReaderThreads[i].fCount = 0;
}
#endif
fInitialized = true;
}
}
RecursiveReaderWriterLock::RecursiveReaderWriterLock()
{
initIfNeeded();
}
void RecursiveReaderWriterLock::lockForSingleWritingThread()
{
this->initIfNeeded();
#if REAL_READER_WRITER_LOCK
pthread_mutex_lock(&fMutex);
pthread_t thisThread = pthread_self();
while ( writerThreadIsAnyThreadBut(thisThread) || readerThreadSetContainsAnotherThread(thisThread) ) {
pthread_cond_wait(&fLockFree, &fMutex);
}
writerThreadRetain(thisThread);
pthread_mutex_unlock(&fMutex);
#else
pthread_mutex_lock(&fMutex);
#endif
}
void RecursiveReaderWriterLock::unlockForSingleWritingThread()
{
this->initIfNeeded();
#if REAL_READER_WRITER_LOCK
pthread_mutex_lock(&fMutex);
if ( writerThreadRelease(pthread_self()) ) {
pthread_cond_broadcast(&fLockFree);
}
pthread_mutex_unlock(&fMutex);
#else
pthread_mutex_unlock(&fMutex);
#endif
}
void RecursiveReaderWriterLock::lockForMultipleReadingThreads()
{
this->initIfNeeded();
#if REAL_READER_WRITER_LOCK
pthread_mutex_lock(&fMutex);
pthread_t thisThread = pthread_self();
while ( writerThreadIsAnyThreadBut(thisThread) || !readerThreadSetRetain(thisThread) ) {
pthread_cond_wait(&fLockFree, &fMutex);
}
pthread_mutex_unlock(&fMutex);
#else
pthread_mutex_lock(&fMutex);
#endif
}
void RecursiveReaderWriterLock::unlockForMultipleReadingThreads()
{
this->initIfNeeded();
#if REAL_READER_WRITER_LOCK
pthread_mutex_lock(&fMutex);
if ( readerThreadSetRelease(pthread_self()) ) {
pthread_cond_broadcast(&fLockFree);
}
pthread_mutex_unlock(&fMutex);
#else
pthread_mutex_unlock(&fMutex);
#endif
}
#if REAL_READER_WRITER_LOCK
bool RecursiveReaderWriterLock::writerThreadIsAnyThreadBut(pthread_t thread)
{
return ( (fWriterThread.fThread != NULL) && (fWriterThread.fThread != thread) );
}
void RecursiveReaderWriterLock::writerThreadRetain(pthread_t thread)
{
++fWriterThread.fCount;
}
bool RecursiveReaderWriterLock::writerThreadRelease(pthread_t thread)
{
return ( --fWriterThread.fCount == 0 );
}
bool RecursiveReaderWriterLock::readerThreadSetRetain(pthread_t thread)
{
for (int i=0; i < kMaxReaderThreads; ++i) {
if ( fReaderThreads[i].fThread == thread ) {
++fReaderThreads[i].fCount;
return true;
}
}
for (int i=0; i < kMaxReaderThreads; ++i) {
if ( fReaderThreads[i].fThread == NULL ) {
fReaderThreads[i].fThread = thread;
fReaderThreads[i].fCount = 1;
return true;
}
}
return false;
}
bool RecursiveReaderWriterLock::readerThreadSetRelease(pthread_t thread)
{
for (int i=0; i < kMaxReaderThreads; ++i) {
if ( fReaderThreads[i].fThread == thread ) {
if ( --fReaderThreads[i].fCount == 0 ) {
fReaderThreads[i].fThread = NULL;
return true;
}
return false;
}
}
return false;
}
bool RecursiveReaderWriterLock::readerThreadSetContainsAnotherThread(pthread_t thread)
{
for (int i=0; i < kMaxReaderThreads; ++i) {
if ( (fReaderThreads[i].fThread != NULL) && (fReaderThreads[i].fThread != thread) )
return true;
}
return false;
}
#endif
static RecursiveReaderWriterLock sLock;
LockReaderHelper::LockReaderHelper()
{
sLock.lockForMultipleReadingThreads();
}
LockReaderHelper::~LockReaderHelper()
{
sLock.unlockForMultipleReadingThreads();
}
LockWriterHelper::LockWriterHelper()
{
sLock.lockForSingleWritingThread();
}
LockWriterHelper::~LockWriterHelper()
{
sLock.unlockForSingleWritingThread();
}
void lockForLazyBinding()
{
sLock.lockForMultipleReadingThreads();
}
void unlockForLazyBinding()
{
sLock.unlockForMultipleReadingThreads();
}