From 8b03d7fe95cc3b5b7f6f6b67d7ce97a8620575a5 Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Tue, 6 Dec 2011 20:42:55 -0800 Subject: w32thread: port fixes to pthread_cond_broadcast() from x264. --- libavcodec/w32pthreads.h | 54 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 8 deletions(-) (limited to 'libavcodec') diff --git a/libavcodec/w32pthreads.h b/libavcodec/w32pthreads.h index c015b87a42..2d1470c5ee 100644 --- a/libavcodec/w32pthreads.h +++ b/libavcodec/w32pthreads.h @@ -115,9 +115,12 @@ static inline int pthread_mutex_unlock(pthread_mutex_t *m) /* for pre-Windows 6.0 platforms we need to define and use our own condition * variable and api */ typedef struct { + pthread_mutex_t mtx_broadcast; pthread_mutex_t mtx_waiter_count; volatile int waiter_count; HANDLE semaphore; + HANDLE waiters_done; + int is_broadcast; } win32_cond_t; static void pthread_cond_init(pthread_cond_t *cond, const void *unused_attr) @@ -136,8 +139,12 @@ static void pthread_cond_init(pthread_cond_t *cond, const void *unused_attr) win32_cond->semaphore = CreateSemaphore(NULL, 0, 0x7fffffff, NULL); if (!win32_cond->semaphore) return; + win32_cond->waiters_done = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!win32_cond->waiters_done) + return; pthread_mutex_init(&win32_cond->mtx_waiter_count, NULL); + pthread_mutex_init(&win32_cond->mtx_broadcast, NULL); } static void pthread_cond_destroy(pthread_cond_t *cond) @@ -149,7 +156,9 @@ static void pthread_cond_destroy(pthread_cond_t *cond) /* non native condition variables */ CloseHandle(win32_cond->semaphore); + CloseHandle(win32_cond->waiters_done); pthread_mutex_destroy(&win32_cond->mtx_waiter_count); + pthread_mutex_destroy(&win32_cond->mtx_broadcast); av_freep(&win32_cond); cond->ptr = NULL; } @@ -157,41 +166,70 @@ static void pthread_cond_destroy(pthread_cond_t *cond) static void pthread_cond_broadcast(pthread_cond_t *cond) { win32_cond_t *win32_cond = cond->ptr; + int have_waiter; + if (cond_broadcast) { cond_broadcast(cond); return; } /* non native condition variables */ + pthread_mutex_lock(&win32_cond->mtx_broadcast); pthread_mutex_lock(&win32_cond->mtx_waiter_count); + have_waiter = 0; + if (win32_cond->waiter_count) { - ReleaseSemaphore(win32_cond->semaphore, win32_cond->waiter_count, NULL); - win32_cond->waiter_count = 0; + win32_cond->is_broadcast = 1; + have_waiter = 1; } - pthread_mutex_unlock(&win32_cond->mtx_waiter_count); + + if (have_waiter) { + ReleaseSemaphore(win32_cond->semaphore, win32_cond->waiter_count, NULL); + pthread_mutex_unlock(&win32_cond->mtx_waiter_count); + WaitForSingleObject(win32_cond->waiters_done, INFINITE); + win32_cond->is_broadcast = 0; + } else + pthread_mutex_unlock(&win32_cond->mtx_waiter_count); + pthread_mutex_unlock(&win32_cond->mtx_broadcast); } static void pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) { win32_cond_t *win32_cond = cond->ptr; + int last_waiter; if (cond_wait) { cond_wait(cond, mutex, INFINITE); return; } /* non native condition variables */ + pthread_mutex_lock(&win32_cond->mtx_broadcast); + pthread_mutex_unlock(&win32_cond->mtx_broadcast); + pthread_mutex_lock(&win32_cond->mtx_waiter_count); win32_cond->waiter_count++; pthread_mutex_unlock(&win32_cond->mtx_waiter_count); + // unlock the external mutex pthread_mutex_unlock(mutex); WaitForSingleObject(win32_cond->semaphore, INFINITE); - pthread_mutex_lock(mutex); + + pthread_mutex_lock(&win32_cond->mtx_waiter_count); + win32_cond->waiter_count--; + last_waiter = !win32_cond->waiter_count && win32_cond->is_broadcast; + pthread_mutex_unlock(&win32_cond->mtx_waiter_count); + + if (last_waiter) + SetEvent(win32_cond->waiters_done); + + // lock the external mutex + return pthread_mutex_lock(mutex); } static void pthread_cond_signal(pthread_cond_t *cond) { win32_cond_t *win32_cond = cond->ptr; + int have_waiter; if (cond_signal) { cond_signal(cond); return; @@ -199,11 +237,11 @@ static void pthread_cond_signal(pthread_cond_t *cond) /* non-native condition variables */ pthread_mutex_lock(&win32_cond->mtx_waiter_count); - if (win32_cond->waiter_count) { - ReleaseSemaphore(win32_cond->semaphore, 1, NULL); - win32_cond->waiter_count--; - } + have_waiter = win32_cond->waiter_count; pthread_mutex_unlock(&win32_cond->mtx_waiter_count); + + if (have_waiter) + ReleaseSemaphore(win32_cond->semaphore, 1, NULL); } static void w32thread_init(void) -- cgit v1.2.3