From fccca4202f9695027288e9d8663daa30cb25fcc3 Mon Sep 17 00:00:00 2001 From: James Zern Date: Thu, 4 Aug 2011 18:40:03 -0700 Subject: [PATCH] windows: add decode threading support Change-Id: Iad923550569ceec1ff469852ec68e66de3f6062b --- Makefile.vc | 3 +- src/dec/thread.c | 124 ++++++++++++++++++++++++++++++++++++++++++++--- src/dec/thread.h | 9 +++- 3 files changed, 128 insertions(+), 8 deletions(-) diff --git a/Makefile.vc b/Makefile.vc index f9b6b4b5..cda55d64 100644 --- a/Makefile.vc +++ b/Makefile.vc @@ -36,7 +36,8 @@ MT = mt.exe CCNODBG = cl.exe /nologo /O2 /DNDEBUG CCDEBUG = cl.exe /nologo /Od /Gm /Zi /D_DEBUG /RTC1 CFLAGS = /Isrc /nologo /W3 /EHsc /FD /c /GS -CFLAGS = $(CFLAGS) /DWIN32 /D_CRT_SECURE_NO_WARNINGS /DHAVE_WINCODEC_H +CFLAGS = $(CFLAGS) /DWIN32 /D_CRT_SECURE_NO_WARNINGS /DWIN32_LEAN_AND_MEAN +CFLAGS = $(CFLAGS) /DHAVE_WINCODEC_H /DWEBP_USE_THREAD LDFLAGS = /LARGEADDRESSAWARE /MANIFEST /NXCOMPAT /DYNAMICBASE $(PLATFORM_LDFLAGS) LNKDLL = link.exe /DLL LNKLIB = link.exe /lib diff --git a/src/dec/thread.c b/src/dec/thread.c index 55e827b0..2255f53e 100644 --- a/src/dec/thread.c +++ b/src/dec/thread.c @@ -18,7 +18,119 @@ extern "C" { #ifdef WEBP_USE_THREAD -static void *WebPWorkerThreadLoop(void *ptr) { // thread loop +#if defined(_WIN32) + +//------------------------------------------------------------------------------ +// simplistic pthread emulation layer + +#include + +// _beginthreadex requires __stdcall +#define THREADFN unsigned int __stdcall +#define THREAD_RETURN(val) (unsigned int)((DWORD_PTR)val) + +static int pthread_create(pthread_t* const thread, const void* attr, + unsigned int (__stdcall *start)(void*), void* arg) { + (void)attr; + *thread = (pthread_t)_beginthreadex(NULL, /* void *security */ + 0, /* unsigned stack_size */ + start, + arg, + 0, /* unsigned initflag */ + NULL); /* unsigned *thrdaddr */ + if (*thread == NULL) return 1; + SetThreadPriority(*thread, THREAD_PRIORITY_ABOVE_NORMAL); + return 0; +} + +static int pthread_join(pthread_t thread, void** value_ptr) { + (void)value_ptr; + return (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0 || + CloseHandle(thread) == 0); +} + +// Mutex +static int pthread_mutex_init(pthread_mutex_t* const mutex, void* mutexattr) { + (void)mutexattr; + InitializeCriticalSection(mutex); + return 0; +} + +static int pthread_mutex_lock(pthread_mutex_t* const mutex) { + EnterCriticalSection(mutex); + return 0; +} + +static int pthread_mutex_unlock(pthread_mutex_t* const mutex) { + LeaveCriticalSection(mutex); + return 0; +} + +static int pthread_mutex_destroy(pthread_mutex_t* const mutex) { + DeleteCriticalSection(mutex); + return 0; +} + +// Condition +static int pthread_cond_destroy(pthread_cond_t* const condition) { + int ok = 1; + ok &= (CloseHandle(condition->waiting_sem_) == 0); + ok &= (CloseHandle(condition->received_sem_) == 0); + ok &= (CloseHandle(condition->signal_event_) == 0); + return ok; +} + +static int pthread_cond_init(pthread_cond_t* const condition, void* cond_attr) { + (void)cond_attr; + condition->waiting_sem_ = CreateSemaphore(NULL, 0, 1, NULL); + condition->received_sem_ = CreateSemaphore(NULL, 0, 1, NULL); + condition->signal_event_ = CreateEvent(NULL, FALSE, FALSE, NULL); + if (condition->waiting_sem_ == NULL || + condition->received_sem_ == NULL || + condition->signal_event_ == NULL) { + pthread_cond_destroy(condition); + return 1; + } + return 0; +} + +static int pthread_cond_signal(pthread_cond_t* const condition) { + int ok = 1; + if (WaitForSingleObject(condition->waiting_sem_, 0) == WAIT_OBJECT_0) { + // a thread is waiting in pthread_cond_wait: allow it to be notified + ok = SetEvent(condition->signal_event_); + // wait until the event is consumed so the signaler cannot consume + // the event via its own pthread_cond_wait. + ok &= (WaitForSingleObject(condition->received_sem_, INFINITE) != + WAIT_OBJECT_0); + } + return !ok; +} + +static int pthread_cond_wait(pthread_cond_t* const condition, + pthread_mutex_t* const mutex) { + int ok; + // note that there is a consumer available so the signal isn't dropped in + // pthread_cond_signal + if (!ReleaseSemaphore(condition->waiting_sem_, 1, NULL)) + return 1; + // now unlock the mutex so pthread_cond_signal may be issued + pthread_mutex_unlock(mutex); + ok = (WaitForSingleObject(condition->signal_event_, INFINITE) == + WAIT_OBJECT_0); + ok &= ReleaseSemaphore(condition->received_sem_, 1, NULL); + pthread_mutex_lock(mutex); + return !ok; +} + +#else // _WIN32 +# define THREADFN void* +# define THREAD_RETURN(val) val +#endif + +//------------------------------------------------------------------------------ + +static THREADFN WebPWorkerThreadLoop(void *ptr) { // thread loop WebPWorker* const worker = (WebPWorker*)ptr; int done = 0; while (!done) { @@ -38,7 +150,7 @@ static void *WebPWorkerThreadLoop(void *ptr) { // thread loop pthread_cond_signal(&worker->condition_); pthread_mutex_unlock(&worker->mutex_); } - return NULL; // Thread is finished + return THREAD_RETURN(NULL); // Thread is finished } // main thread state control @@ -60,7 +172,7 @@ static void WebPWorkerChangeState(WebPWorker* const worker, #endif -//----------------------------------------------------------------------------- +//------------------------------------------------------------------------------ void WebPWorkerInit(WebPWorker* const worker) { memset(worker, 0, sizeof(*worker)); @@ -80,12 +192,12 @@ int WebPWorkerReset(WebPWorker* const worker) { worker->had_error = 0; if (worker->status_ < OK) { #ifdef WEBP_USE_THREAD - if (pthread_mutex_init(&worker->mutex_, 0) || - pthread_cond_init(&worker->condition_, 0)) { + if (pthread_mutex_init(&worker->mutex_, NULL) || + pthread_cond_init(&worker->condition_, NULL)) { return 0; } pthread_mutex_lock(&worker->mutex_); - ok = !pthread_create(&worker->thread_, 0, WebPWorkerThreadLoop, worker); + ok = !pthread_create(&worker->thread_, NULL, WebPWorkerThreadLoop, worker); if (ok) worker->status_ = OK; pthread_mutex_unlock(&worker->mutex_); #else diff --git a/src/dec/thread.h b/src/dec/thread.h index 1cd0d1fd..b5500e81 100644 --- a/src/dec/thread.h +++ b/src/dec/thread.h @@ -20,7 +20,14 @@ extern "C" { #if defined(_WIN32) -#undef WEBP_USE_THREAD +#include +typedef HANDLE pthread_t; +typedef CRITICAL_SECTION pthread_mutex_t; +typedef struct { + HANDLE waiting_sem_; + HANDLE received_sem_; + HANDLE signal_event_; +} pthread_cond_t; #else