diff options
author | Steven Walters <kemuri9@gmail.com> | 2011-10-09 21:38:35 +0200 |
---|---|---|
committer | Janne Grunau <janne-libav@jannau.net> | 2011-10-16 21:45:16 +0200 |
commit | 27237d524e56210992b18486924894bb4f3fdbb8 (patch) | |
tree | 02477ac46ef62e3a9293a25b365698ed628e4038 /libavcodec/w32pthreads.h | |
parent | b44522981ce1f5da1d4ec62950b0933fc18ac223 (diff) | |
download | ffmpeg-27237d524e56210992b18486924894bb4f3fdbb8.tar.gz |
w32threads: support for frame multithreading
Replace our incomplete w32threads implementation with x264's pthreads
w32threads wrapper.
Relicensed to LGPL with kind permission by Pegasys Inc.
Signed-off-by: Janne Grunau <janne-libav@jannau.net>
Diffstat (limited to 'libavcodec/w32pthreads.h')
-rw-r--r-- | libavcodec/w32pthreads.h | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/libavcodec/w32pthreads.h b/libavcodec/w32pthreads.h new file mode 100644 index 0000000000..7774817518 --- /dev/null +++ b/libavcodec/w32pthreads.h @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2010-2011 x264 project + * + * Authors: Steven Walters <kemuri9@gmail.com> + * Pegasys Inc. <http://www.pegasys-inc.com> + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * w32threads to pthreads wrapper + */ + +#ifndef AVCODEC_W32PTHREADS_H +#define AVCODEC_W32PTHREADS_H + +/* Build up a pthread-like API using underlying Windows API. Have only static + * methods so as to not conflict with a potentially linked in pthread-win32 + * library. + * As most functions here are used without checking return values, + * only implement return values as necessary. */ + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <process.h> + +typedef struct { + void *handle; + void *(*func)(void* arg); + void *arg; + void *ret; +} pthread_t; + +/* the conditional variable api for windows 6.0+ uses critical sections and + * not mutexes */ +typedef CRITICAL_SECTION pthread_mutex_t; + +/* This is the CONDITIONAL_VARIABLE typedef for using Window's native + * conditional variables on kernels 6.0+. + * MinGW does not currently have this typedef. */ +typedef struct { + void *ptr; +} pthread_cond_t; + +/* function pointers to conditional variable API on windows 6.0+ kernels */ +static void (WINAPI *cond_broadcast)(pthread_cond_t *cond); +static void (WINAPI *cond_init)(pthread_cond_t *cond); +static void (WINAPI *cond_signal)(pthread_cond_t *cond); +static BOOL (WINAPI *cond_wait)(pthread_cond_t *cond, pthread_mutex_t *mutex, + DWORD milliseconds); + +static unsigned __stdcall attribute_align_arg win32thread_worker(void *arg) +{ + pthread_t *h = arg; + h->ret = h->func(h->arg); + return 0; +} + +static int pthread_create(pthread_t *thread, const void *unused_attr, + void *(*start_routine)(void*), void *arg) +{ + thread->func = start_routine; + thread->arg = arg; + thread->handle = (void*)_beginthreadex(NULL, 0, win32thread_worker, thread, + 0, NULL); + return !thread->handle; +} + +static void pthread_join(pthread_t thread, void **value_ptr) +{ + DWORD ret = WaitForSingleObject(thread.handle, INFINITE); + if (ret != WAIT_OBJECT_0) + return; + if (value_ptr) + *value_ptr = thread.ret; + CloseHandle(thread.handle); +} + +#define pthread_mutex_init(m, a) InitializeCriticalSection(m) +#define pthread_mutex_destroy(m) DeleteCriticalSection(m) +#define pthread_mutex_lock(m) EnterCriticalSection(m) +#define pthread_mutex_unlock(m) LeaveCriticalSection(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_waiter_count; + volatile int waiter_count; + HANDLE semaphore; +} win32_cond_t; + +static void pthread_cond_init(pthread_cond_t *cond, const void *unused_attr) +{ + win32_cond_t *win32_cond = NULL; + if (cond_init) { + cond_init(cond); + return; + } + + /* non native condition variables */ + win32_cond = av_mallocz(sizeof(win32_cond_t)); + if (!win32_cond) + return; + cond->ptr = win32_cond; + win32_cond->semaphore = CreateSemaphore(NULL, 0, 0x7fffffff, NULL); + if (!win32_cond->semaphore) + return; + + pthread_mutex_init(&win32_cond->mtx_waiter_count, NULL); +} + +static void pthread_cond_destroy(pthread_cond_t *cond) +{ + win32_cond_t *win32_cond = cond->ptr; + /* native condition variables do not destroy */ + if (cond_init) + return; + + /* non native condition variables */ + CloseHandle(win32_cond->semaphore); + pthread_mutex_destroy(&win32_cond->mtx_waiter_count); + av_freep(&win32_cond); + cond->ptr = NULL; +} + +static void pthread_cond_broadcast(pthread_cond_t *cond) +{ + win32_cond_t *win32_cond = cond->ptr; + if (cond_broadcast) { + cond_broadcast(cond); + return; + } + + /* non native condition variables */ + pthread_mutex_lock(&win32_cond->mtx_waiter_count); + if (win32_cond->waiter_count) { + ReleaseSemaphore(win32_cond->semaphore, win32_cond->waiter_count, NULL); + win32_cond->waiter_count = 0; + } + pthread_mutex_unlock(&win32_cond->mtx_waiter_count); +} + +static void pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + win32_cond_t *win32_cond = cond->ptr; + if (cond_wait) { + cond_wait(cond, mutex, INFINITE); + return; + } + + /* non native condition variables */ + pthread_mutex_lock(&win32_cond->mtx_waiter_count); + win32_cond->waiter_count++; + pthread_mutex_unlock(&win32_cond->mtx_waiter_count); + + pthread_mutex_unlock(mutex); + WaitForSingleObject(win32_cond->semaphore, INFINITE); + pthread_mutex_lock(mutex); +} + +static void pthread_cond_signal(pthread_cond_t *cond) +{ + win32_cond_t *win32_cond = cond->ptr; + if (cond_signal) { + cond_signal(cond); + return; + } + + /* 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--; + } + pthread_mutex_unlock(&win32_cond->mtx_waiter_count); +} + +static void w32thread_init(void) +{ + HANDLE kernel_dll = GetModuleHandle(TEXT("kernel32.dll")); + /* if one is available, then they should all be available */ + cond_init = + (void*)GetProcAddress(kernel_dll, "InitializeConditionVariable"); + cond_broadcast = + (void*)GetProcAddress(kernel_dll, "WakeAllConditionVariable"); + cond_signal = + (void*)GetProcAddress(kernel_dll, "WakeConditionVariable"); + cond_wait = + (void*)GetProcAddress(kernel_dll, "SleepConditionVariableCS"); +} + +#endif /* AVCODEC_W32PTHREADS_H */ |