mirror of https://github.com/OpenTTD/OpenTTD.git
(svn r26349) -Add: Optional recursive locking of mutexes.
This commit is contained in:
parent
b2ca2e2979
commit
7ac18c0f22
|
@ -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.
|
||||||
|
|
|
@ -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() {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue