(svn r26349) -Add: Optional recursive locking of mutexes.

This commit is contained in:
frosch 2014-02-16 21:37:05 +00:00
parent b2ca2e2979
commit 7ac18c0f22
5 changed files with 66 additions and 15 deletions

View File

@ -66,13 +66,19 @@ public:
/** /**
* Begin the critical section * Begin the critical section
* @param allow_recursive Whether recursive locking is intentional.
* If false, NOT_REACHED() will be called when the mutex is already locked
* by the current thread.
*/ */
virtual void BeginCritical() = 0; virtual void BeginCritical(bool allow_recursive = false) = 0;
/** /**
* End of the critical section * End of the critical section
* @param allow_recursive Whether recursive unlocking is intentional.
* If false, NOT_REACHED() will be called when the mutex was locked more
* than once by the current thread.
*/ */
virtual void EndCritical() = 0; virtual void EndCritical(bool allow_recursive = false) = 0;
/** /**
* Wait for a signal to be send. * Wait for a signal to be send.

View File

@ -21,8 +21,8 @@
/** Mutex that doesn't do locking because it ain't needed when there're no threads */ /** Mutex that doesn't do locking because it ain't needed when there're no threads */
class ThreadMutex_None : public ThreadMutex { class ThreadMutex_None : public ThreadMutex {
public: public:
virtual void BeginCritical() {} virtual void BeginCritical(bool allow_recursive = false) {}
virtual void EndCritical() {} virtual void EndCritical(bool allow_recursive = false) {}
virtual void WaitForSignal() {} virtual void WaitForSignal() {}
virtual void SendSignal() {} virtual void SendSignal() {}
}; };

View File

@ -95,9 +95,10 @@ class ThreadMutex_OS2 : public ThreadMutex {
private: private:
HMTX mutex; ///< The mutex. HMTX mutex; ///< The mutex.
HEV event; ///< Event for waiting. HEV event; ///< Event for waiting.
uint recursive_count; ///< Recursive lock count.
public: public:
ThreadMutex_OS2() ThreadMutex_OS2() : recursive_count(0)
{ {
DosCreateMutexSem(NULL, &mutex, 0, FALSE); DosCreateMutexSem(NULL, &mutex, 0, FALSE);
DosCreateEventSem(NULL, &event, 0, FALSE); DosCreateEventSem(NULL, &event, 0, FALSE);
@ -109,21 +110,30 @@ public:
DosCloseEventSem(event); DosCloseEventSem(event);
} }
/* virtual */ void BeginCritical() /* virtual */ void BeginCritical(bool allow_recursive = false)
{ {
/* os2 mutex is recursive by itself */
DosRequestMutexSem(mutex, (unsigned long) SEM_INDEFINITE_WAIT); DosRequestMutexSem(mutex, (unsigned long) SEM_INDEFINITE_WAIT);
this->recursive_count++;
if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
} }
/* virtual */ void EndCritical() /* virtual */ void EndCritical(bool allow_recursive = false)
{ {
if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
this->recursive_count--;
DosReleaseMutexSem(mutex); DosReleaseMutexSem(mutex);
} }
/* virtual */ void WaitForSignal() /* virtual */ void WaitForSignal()
{ {
assert(this->recursive_count == 1); // Do we need to call Begin/EndCritical multiple times otherwise?
uint old_recursive_count = this->recursive_count;
this->recursive_count = 0;
this->EndCritical(); this->EndCritical();
DosWaitEventSem(event, SEM_INDEFINITE_WAIT); DosWaitEventSem(event, SEM_INDEFINITE_WAIT);
this->BeginCritical(); this->BeginCritical();
this->recursive_count = this->recursive_count;
} }
/* virtual */ void SendSignal() /* virtual */ void SendSignal()

View File

@ -98,9 +98,11 @@ private:
pthread_mutex_t mutex; ///< The actual mutex. pthread_mutex_t mutex; ///< The actual mutex.
pthread_cond_t condition; ///< Data for conditional waiting. pthread_cond_t condition; ///< Data for conditional waiting.
pthread_mutexattr_t attr; ///< Attributes set for the mutex. pthread_mutexattr_t attr; ///< Attributes set for the mutex.
pthread_t owner; ///< Owning thread of the mutex.
uint recursive_count; ///< Recursive lock count.
public: public:
ThreadMutex_pthread() ThreadMutex_pthread() : owner(0), recursive_count(0)
{ {
pthread_mutexattr_init(&this->attr); pthread_mutexattr_init(&this->attr);
pthread_mutexattr_settype(&this->attr, PTHREAD_MUTEX_ERRORCHECK); pthread_mutexattr_settype(&this->attr, PTHREAD_MUTEX_ERRORCHECK);
@ -116,22 +118,45 @@ public:
assert(err != EBUSY); assert(err != EBUSY);
} }
/* virtual */ void BeginCritical() bool IsOwnedByCurrentThread() const
{ {
int err = pthread_mutex_lock(&this->mutex); return this->owner == pthread_self();
assert(err == 0);
} }
/* virtual */ void EndCritical() /* virtual */ void BeginCritical(bool allow_recursive = false)
{ {
/* pthread mutex is not recursive by itself */
if (this->IsOwnedByCurrentThread()) {
if (!allow_recursive) NOT_REACHED();
} else {
int err = pthread_mutex_lock(&this->mutex);
assert(err == 0);
assert(this->recursive_count == 0);
this->owner = pthread_self();
}
this->recursive_count++;
}
/* virtual */ void EndCritical(bool allow_recursive = false)
{
assert(this->IsOwnedByCurrentThread());
if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
this->recursive_count--;
if (this->recursive_count != 0) return;
this->owner = 0;
int err = pthread_mutex_unlock(&this->mutex); int err = pthread_mutex_unlock(&this->mutex);
assert(err == 0); assert(err == 0);
} }
/* virtual */ void WaitForSignal() /* virtual */ void WaitForSignal()
{ {
uint old_recursive_count = this->recursive_count;
this->recursive_count = 0;
this->owner = 0;
int err = pthread_cond_wait(&this->condition, &this->mutex); int err = pthread_cond_wait(&this->condition, &this->mutex);
assert(err == 0); assert(err == 0);
this->owner = pthread_self();
this->recursive_count = old_recursive_count;
} }
/* virtual */ void SendSignal() /* virtual */ void SendSignal()

View File

@ -108,9 +108,10 @@ class ThreadMutex_Win32 : public ThreadMutex {
private: private:
CRITICAL_SECTION critical_section; ///< The critical section we would enter. CRITICAL_SECTION critical_section; ///< The critical section we would enter.
HANDLE event; ///< Event for signalling. HANDLE event; ///< Event for signalling.
uint recursive_count; ///< Recursive lock count.
public: public:
ThreadMutex_Win32() ThreadMutex_Win32() : recursive_count(0)
{ {
InitializeCriticalSection(&this->critical_section); InitializeCriticalSection(&this->critical_section);
this->event = CreateEvent(NULL, FALSE, FALSE, NULL); this->event = CreateEvent(NULL, FALSE, FALSE, NULL);
@ -122,21 +123,30 @@ public:
CloseHandle(this->event); CloseHandle(this->event);
} }
/* virtual */ void BeginCritical() /* virtual */ void BeginCritical(bool allow_recursive = false)
{ {
/* windows mutex is recursive by itself */
EnterCriticalSection(&this->critical_section); EnterCriticalSection(&this->critical_section);
this->recursive_count++;
if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
} }
/* virtual */ void EndCritical() /* virtual */ void EndCritical(bool allow_recursive = false)
{ {
if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
this->recursive_count--;
LeaveCriticalSection(&this->critical_section); LeaveCriticalSection(&this->critical_section);
} }
/* virtual */ void WaitForSignal() /* virtual */ void WaitForSignal()
{ {
assert(this->recursive_count == 1); // Do we need to call Begin/EndCritical multiple times otherwise?
uint old_recursive_count = this->recursive_count;
this->recursive_count = 0;
this->EndCritical(); this->EndCritical();
WaitForSingleObject(this->event, INFINITE); WaitForSingleObject(this->event, INFINITE);
this->BeginCritical(); this->BeginCritical();
this->recursive_count = this->recursive_count;
} }
/* virtual */ void SendSignal() /* virtual */ void SendSignal()