add TryLock

add semaphores
This commit is contained in:
Glenn Maynard
2004-06-14 05:21:46 +00:00
parent 34b3862833
commit cf9d31917f
5 changed files with 223 additions and 44 deletions
+15 -11
View File
@@ -7,17 +7,6 @@ class RageMutex;
class ThreadImpl
{
#if defined(PID_BASED_THREADS)
/* Keep a list of child PIDs, so we can send them SIGKILL. This has an
* added bonus: if this is corrupted, we'll just send signals and they'll
* fail; we won't blow up (unless we're root). */
// int pid;
#endif
#if defined(DARWIN)
// thread_act_t ThreadHandle;
#endif
public:
virtual ~ThreadImpl() { }
virtual void Halt( bool Kill ) = 0;
@@ -46,15 +35,30 @@ public:
* all other errors should fail with an assertion. */
virtual bool Lock() = 0;
/* Non-blocking lock. If locking the mutex would block because the mutex is already
* locked by another thread, return false; otherwise return true and lock the mutex. */
virtual bool TryLock() = 0;
/* Unlock the mutex. This must only be called when the mutex is locked; implementations
* may fail with an assertion if the mutex is not locked. */
virtual void Unlock() = 0;
};
class SemaImpl
{
public:
virtual ~SemaImpl() { }
virtual int GetValue() const = 0;
virtual void Post() = 0;
virtual bool Wait() = 0;
virtual bool TryWait() = 0;
};
/* These functions must be implemented by the thread implementation. */
ThreadImpl *MakeThread( int (*fn)(void *), void *data );
ThreadImpl *MakeThisThread();
MutexImpl *MakeMutex( RageMutex *pParent );
SemaImpl *MakeSemaphore( int iInitialValue );
uint64_t GetThisThreadId();
/* Since ThreadId is implementation-defined, we can't define a universal invalid
@@ -145,6 +145,11 @@ bool MutexImpl_Pthreads::Lock()
case 0:
return true;
case EINTR:
/* Ignore it. */
++tries;
continue;
case ETIMEDOUT:
/* Timed out. Probably deadlocked. Try again one more time, with a smaller
* timeout, just in case we're debugging and happened to stop while waiting
@@ -153,19 +158,35 @@ bool MutexImpl_Pthreads::Lock()
break;
default:
RageException::Throw( "pthread_mutex_timedlock: %s", strerror(ret) );
FAIL_M( ssprintf("pthread_mutex_timedlock: %s", strerror(ret)) );
}
}
return false;
#else
int ret = pthread_mutex_lock( &mutex );
if( ret )
RageException::Throw( "pthread_mutex_lock failed: %s", strerror(ret) );
int ret;
do
{
CHECKPOINT;
ret = pthread_mutex_lock( &mutex );
}
while( ret == -1 && ret == EINTR );
ASSERT_M( ret == 0, ssprintf("pthread_mutex_lock: %s", strerror(errno)) );
return true;
#endif
}
bool MutexImpl_Pthreads::TryLock()
{
int ret = pthread_mutex_trylock( &mutex );
if( ret == EBUSY )
return false;
if( ret )
RageException::Throw( "pthread_mutex_lock failed: %s", strerror(ret) );
return true;
}
void MutexImpl_Pthreads::Unlock()
{
@@ -191,6 +212,58 @@ MutexImpl *MakeMutex( RageMutex *pParent )
return new MutexImpl_Pthreads( pParent );
}
SemaImpl_Pthreads::SemaImpl_Pthreads( int iInitialValue )
{
sem_init( &sem, 0, iInitialValue );
}
SemaImpl_Pthreads::~SemaImpl_Pthreads()
{
sem_destroy( &sem );
}
int SemaImpl_Pthreads::GetValue() const
{
int ret;
sem_getvalue( &sem, &ret );
return ret;
}
void SemaImpl_Pthreads::Post()
{
sem_post( &sem );
}
bool SemaImpl_Pthreads::Wait()
{
int ret;
do
{
CHECKPOINT;
ret = sem_wait( &sem );
}
while( ret == -1 && errno == EINTR );
ASSERT_M( ret == 0, ssprintf("sem_wait: %s", strerror(errno)) );
return true;
}
bool SemaImpl_Pthreads::TryWait()
{
int ret = sem_trywait( &sem );
if( ret == EBUSY )
return false;
if( ret )
RageException::Throw( "sem_trywait failed: %s", strerror(ret) );
return true;
}
SemaImpl *MakeSemaphore( int iInitialValue )
{
return new SemaImpl_Pthreads( iInitialValue );
}
/*
* (c) 2001-2004 Glenn Maynard
+20 -6
View File
@@ -10,9 +10,6 @@
class ThreadImpl_Pthreads: public ThreadImpl
{
public:
// HANDLE ThreadHandle;
// DWORD ThreadId;
pthread_t thread;
#if defined(PID_BASED_THREADS)
@@ -36,15 +33,32 @@ public:
int Wait();
};
struct MutexImpl_Pthreads: public MutexImpl
class MutexImpl_Pthreads: public MutexImpl
{
pthread_mutex_t mutex;
public:
MutexImpl_Pthreads( RageMutex *parent );
~MutexImpl_Pthreads();
bool Lock();
bool TryLock();
void Unlock();
private:
pthread_mutex_t mutex;
};
class SemaImpl_Pthreads: public SemaImpl
{
public:
SemaImpl_Pthreads( int iInitialValue );
~SemaImpl_Pthreads();
int GetValue() const;
void Post();
bool Wait();
bool TryWait();
private:
sem_t sem;
};
#endif
+88 -20
View File
@@ -94,6 +94,29 @@ MutexImpl_Win32::~MutexImpl_Win32()
CloseHandle( mutex );
}
static bool SimpleWaitForSingleObject( HANDLE h, DWORD ms )
{
DWORD ret = WaitForSingleObject( h, ms );
switch( ret )
{
case WAIT_OBJECT_0:
return true;
case WAIT_TIMEOUT:
return false;
case WAIT_ABANDONED:
/* The docs aren't particular about what this does, but it should never happen. */
FAIL_M( "WAIT_ABANDONED" );
case WAIT_FAILED:
FAIL_M( werr_ssprintf(GetLastError(), "WaitForSingleObject") );
default:
FAIL_M( "unknown" );
}
}
bool MutexImpl_Win32::Lock()
{
int len = 15000;
@@ -102,33 +125,24 @@ bool MutexImpl_Win32::Lock()
while( tries-- )
{
/* Wait for fifteen seconds. If it takes longer than that, we're probably deadlocked. */
DWORD ret = WaitForSingleObject( mutex, len );
switch( ret )
{
case WAIT_ABANDONED:
/* The docs aren't particular about what this does, but it should never happen. */
ASSERT( 0 );
break;
case WAIT_OBJECT_0:
if( SimpleWaitForSingleObject( mutex, len ) )
return true;
case WAIT_TIMEOUT:
/* Timed out. Probably deadlocked. Try again one more time, with a smaller
* timeout, just in case we're debugging and happened to stop while waiting
* on the mutex. */
len = 1000;
break;
case WAIT_FAILED:
FAIL_M( werr_ssprintf(GetLastError(), "WaitForSingleObject(%s)", this->m_Parent->GetName().c_str()) );
}
/* Timed out; probably deadlocked. Try again one more time, with a smaller
* timeout, just in case we're debugging and happened to stop while waiting
* on the mutex. */
len = 1000;
}
return false;
}
bool MutexImpl_Win32::TryLock()
{
return SimpleWaitForSingleObject( mutex, 0 );
}
void MutexImpl_Win32::Unlock()
{
const bool ret = !!ReleaseMutex( mutex );
@@ -154,6 +168,60 @@ MutexImpl *MakeMutex( RageMutex *pParent )
return new MutexImpl_Win32( pParent );
}
SemaImpl_Win32::SemaImpl_Win32( int iInitialValue )
{
sem = CreateSemaphore( NULL, iInitialValue, 999999999, NULL );
m_iCounter = iInitialValue;
}
SemaImpl_Win32::~SemaImpl_Win32()
{
CloseHandle( sem );
}
void SemaImpl_Win32::Post()
{
++m_iCounter;
ReleaseSemaphore( sem, 1, NULL );
}
bool SemaImpl_Win32::Wait()
{
int len = 15000;
int tries = 2;
while( tries-- )
{
/* Wait for fifteen seconds. If it takes longer than that, we're probably deadlocked. */
if( SimpleWaitForSingleObject( sem, len ) )
{
--m_iCounter;
return true;
}
/* Timed out; probably deadlocked. Try again one more time, with a smaller
* timeout, just in case we're debugging and happened to stop while waiting
* on the mutex. */
len = 1000;
}
return false;
}
bool SemaImpl_Win32::TryWait()
{
if( !SimpleWaitForSingleObject( sem, 0 ) )
return false;
--m_iCounter;
return true;
}
SemaImpl *MakeSemaphore( int iInitialValue )
{
return new SemaImpl_Win32( iInitialValue );
}
/*
* (c) 2001-2004 Glenn Maynard
* All rights reserved.
+23 -3
View File
@@ -20,15 +20,35 @@ public:
int Wait();
};
struct MutexImpl_Win32: public MutexImpl
class MutexImpl_Win32: public MutexImpl
{
HANDLE mutex;
public:
MutexImpl_Win32( RageMutex *parent );
~MutexImpl_Win32();
bool Lock();
bool TryLock();
void Unlock();
private:
HANDLE mutex;
};
class SemaImpl_Win32: public SemaImpl
{
public:
SemaImpl_Win32( int iInitialValue );
~SemaImpl_Win32();
int GetValue() const { return m_iCounter; }
void Post();
bool Wait();
bool TryWait();
private:
HANDLE sem;
/* We have to track the count ourself, since Windows gives no way to query it. */
int m_iCounter;
};
#endif