Merge branch 'lj/mingw-pthread-cond'
Code simplification. * lj/mingw-pthread-cond: win32: replace pthread_cond_*() with much simpler code
This commit is contained in:
commit
06a2d241cf
@ -56,141 +56,3 @@ pthread_t pthread_self(void)
|
||||
t.tid = GetCurrentThreadId();
|
||||
return t;
|
||||
}
|
||||
|
||||
int pthread_cond_init(pthread_cond_t *cond, const void *unused)
|
||||
{
|
||||
cond->waiters = 0;
|
||||
cond->was_broadcast = 0;
|
||||
InitializeCriticalSection(&cond->waiters_lock);
|
||||
|
||||
cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
|
||||
if (!cond->sema)
|
||||
die("CreateSemaphore() failed");
|
||||
|
||||
cond->continue_broadcast = CreateEvent(NULL, /* security */
|
||||
FALSE, /* auto-reset */
|
||||
FALSE, /* not signaled */
|
||||
NULL); /* name */
|
||||
if (!cond->continue_broadcast)
|
||||
die("CreateEvent() failed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_destroy(pthread_cond_t *cond)
|
||||
{
|
||||
CloseHandle(cond->sema);
|
||||
CloseHandle(cond->continue_broadcast);
|
||||
DeleteCriticalSection(&cond->waiters_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex)
|
||||
{
|
||||
int last_waiter;
|
||||
|
||||
EnterCriticalSection(&cond->waiters_lock);
|
||||
cond->waiters++;
|
||||
LeaveCriticalSection(&cond->waiters_lock);
|
||||
|
||||
/*
|
||||
* Unlock external mutex and wait for signal.
|
||||
* NOTE: we've held mutex locked long enough to increment
|
||||
* waiters count above, so there's no problem with
|
||||
* leaving mutex unlocked before we wait on semaphore.
|
||||
*/
|
||||
LeaveCriticalSection(mutex);
|
||||
|
||||
/* let's wait - ignore return value */
|
||||
WaitForSingleObject(cond->sema, INFINITE);
|
||||
|
||||
/*
|
||||
* Decrease waiters count. If we are the last waiter, then we must
|
||||
* notify the broadcasting thread that it can continue.
|
||||
* But if we continued due to cond_signal, we do not have to do that
|
||||
* because the signaling thread knows that only one waiter continued.
|
||||
*/
|
||||
EnterCriticalSection(&cond->waiters_lock);
|
||||
cond->waiters--;
|
||||
last_waiter = cond->was_broadcast && cond->waiters == 0;
|
||||
LeaveCriticalSection(&cond->waiters_lock);
|
||||
|
||||
if (last_waiter) {
|
||||
/*
|
||||
* cond_broadcast was issued while mutex was held. This means
|
||||
* that all other waiters have continued, but are contending
|
||||
* for the mutex at the end of this function because the
|
||||
* broadcasting thread did not leave cond_broadcast, yet.
|
||||
* (This is so that it can be sure that each waiter has
|
||||
* consumed exactly one slice of the semaphor.)
|
||||
* The last waiter must tell the broadcasting thread that it
|
||||
* can go on.
|
||||
*/
|
||||
SetEvent(cond->continue_broadcast);
|
||||
/*
|
||||
* Now we go on to contend with all other waiters for
|
||||
* the mutex. Auf in den Kampf!
|
||||
*/
|
||||
}
|
||||
/* lock external mutex again */
|
||||
EnterCriticalSection(mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* IMPORTANT: This implementation requires that pthread_cond_signal
|
||||
* is called while the mutex is held that is used in the corresponding
|
||||
* pthread_cond_wait calls!
|
||||
*/
|
||||
int pthread_cond_signal(pthread_cond_t *cond)
|
||||
{
|
||||
int have_waiters;
|
||||
|
||||
EnterCriticalSection(&cond->waiters_lock);
|
||||
have_waiters = cond->waiters > 0;
|
||||
LeaveCriticalSection(&cond->waiters_lock);
|
||||
|
||||
/*
|
||||
* Signal only when there are waiters
|
||||
*/
|
||||
if (have_waiters)
|
||||
return ReleaseSemaphore(cond->sema, 1, NULL) ?
|
||||
0 : err_win_to_posix(GetLastError());
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* DOUBLY IMPORTANT: This implementation requires that pthread_cond_broadcast
|
||||
* is called while the mutex is held that is used in the corresponding
|
||||
* pthread_cond_wait calls!
|
||||
*/
|
||||
int pthread_cond_broadcast(pthread_cond_t *cond)
|
||||
{
|
||||
EnterCriticalSection(&cond->waiters_lock);
|
||||
|
||||
if ((cond->was_broadcast = cond->waiters > 0)) {
|
||||
/* wake up all waiters */
|
||||
ReleaseSemaphore(cond->sema, cond->waiters, NULL);
|
||||
LeaveCriticalSection(&cond->waiters_lock);
|
||||
/*
|
||||
* At this point all waiters continue. Each one takes its
|
||||
* slice of the semaphor. Now it's our turn to wait: Since
|
||||
* the external mutex is held, no thread can leave cond_wait,
|
||||
* yet. For this reason, we can be sure that no thread gets
|
||||
* a chance to eat *more* than one slice. OTOH, it means
|
||||
* that the last waiter must send us a wake-up.
|
||||
*/
|
||||
WaitForSingleObject(cond->continue_broadcast, INFINITE);
|
||||
/*
|
||||
* Since the external mutex is held, no thread can enter
|
||||
* cond_wait, and, hence, it is safe to reset this flag
|
||||
* without cond->waiters_lock held.
|
||||
*/
|
||||
cond->was_broadcast = 0;
|
||||
} else {
|
||||
LeaveCriticalSection(&cond->waiters_lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -32,27 +32,13 @@ typedef int pthread_mutexattr_t;
|
||||
#define pthread_mutexattr_settype(a, t) 0
|
||||
#define PTHREAD_MUTEX_RECURSIVE 0
|
||||
|
||||
/*
|
||||
* Implement simple condition variable for Windows threads, based on ACE
|
||||
* implementation.
|
||||
*
|
||||
* See original implementation: http://bit.ly/1vkDjo
|
||||
* ACE homepage: http://www.cse.wustl.edu/~schmidt/ACE.html
|
||||
* See also: http://www.cse.wustl.edu/~schmidt/win32-cv-1.html
|
||||
*/
|
||||
typedef struct {
|
||||
LONG waiters;
|
||||
int was_broadcast;
|
||||
CRITICAL_SECTION waiters_lock;
|
||||
HANDLE sema;
|
||||
HANDLE continue_broadcast;
|
||||
} pthread_cond_t;
|
||||
#define pthread_cond_t CONDITION_VARIABLE
|
||||
|
||||
extern int pthread_cond_init(pthread_cond_t *cond, const void *unused);
|
||||
extern int pthread_cond_destroy(pthread_cond_t *cond);
|
||||
extern int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex);
|
||||
extern int pthread_cond_signal(pthread_cond_t *cond);
|
||||
extern int pthread_cond_broadcast(pthread_cond_t *cond);
|
||||
#define pthread_cond_init(a,b) InitializeConditionVariable((a))
|
||||
#define pthread_cond_destroy(a) do {} while (0)
|
||||
#define pthread_cond_wait(a,b) return_0(SleepConditionVariableCS((a), (b), INFINITE))
|
||||
#define pthread_cond_signal WakeConditionVariable
|
||||
#define pthread_cond_broadcast WakeAllConditionVariable
|
||||
|
||||
/*
|
||||
* Simple thread creation implementation using pthread API
|
||||
|
Loading…
Reference in New Issue
Block a user