Libav
w32pthreads.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2010-2011 x264 project
3  *
4  * Authors: Steven Walters <kemuri9@gmail.com>
5  * Pegasys Inc. <http://www.pegasys-inc.com>
6  *
7  * This file is part of Libav.
8  *
9  * Libav is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * Libav is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with Libav; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23 
29 #ifndef LIBAV_COMPAT_W32PTHREADS_H
30 #define LIBAV_COMPAT_W32PTHREADS_H
31 
32 /* Build up a pthread-like API using underlying Windows API. Have only static
33  * methods so as to not conflict with a potentially linked in pthread-win32
34  * library.
35  * As most functions here are used without checking return values,
36  * only implement return values as necessary. */
37 
38 #define WIN32_LEAN_AND_MEAN
39 #include <windows.h>
40 #include <process.h>
41 
42 #include "libavutil/internal.h"
43 #include "libavutil/mem.h"
44 
45 typedef struct pthread_t {
46  void *handle;
47  void *(*func)(void* arg);
48  void *arg;
49  void *ret;
50 } pthread_t;
51 
52 /* the conditional variable api for windows 6.0+ uses critical sections and
53  * not mutexes */
54 typedef CRITICAL_SECTION pthread_mutex_t;
55 
56 /* This is the CONDITIONAL_VARIABLE typedef for using Window's native
57  * conditional variables on kernels 6.0+.
58  * MinGW does not currently have this typedef. */
59 typedef struct pthread_cond_t {
60  void *ptr;
62 
63 /* function pointers to conditional variable API on windows 6.0+ kernels */
64 #if _WIN32_WINNT < 0x0600
65 static void (WINAPI *cond_broadcast)(pthread_cond_t *cond);
66 static void (WINAPI *cond_init)(pthread_cond_t *cond);
67 static void (WINAPI *cond_signal)(pthread_cond_t *cond);
68 static BOOL (WINAPI *cond_wait)(pthread_cond_t *cond, pthread_mutex_t *mutex,
69  DWORD milliseconds);
70 #else
71 #define cond_init InitializeConditionVariable
72 #define cond_broadcast WakeAllConditionVariable
73 #define cond_signal WakeConditionVariable
74 #define cond_wait SleepConditionVariableCS
75 #endif
76 
77 static unsigned __stdcall attribute_align_arg win32thread_worker(void *arg)
78 {
79  pthread_t *h = arg;
80  h->ret = h->func(h->arg);
81  return 0;
82 }
83 
84 static int pthread_create(pthread_t *thread, const void *unused_attr,
85  void *(*start_routine)(void*), void *arg)
86 {
87  thread->func = start_routine;
88  thread->arg = arg;
89  thread->handle = (void*)_beginthreadex(NULL, 0, win32thread_worker, thread,
90  0, NULL);
91  return !thread->handle;
92 }
93 
94 static void pthread_join(pthread_t thread, void **value_ptr)
95 {
96  DWORD ret = WaitForSingleObject(thread.handle, INFINITE);
97  if (ret != WAIT_OBJECT_0)
98  return;
99  if (value_ptr)
100  *value_ptr = thread.ret;
101  CloseHandle(thread.handle);
102 }
103 
104 static inline int pthread_mutex_init(pthread_mutex_t *m, void* attr)
105 {
106  InitializeCriticalSection(m);
107  return 0;
108 }
110 {
111  DeleteCriticalSection(m);
112  return 0;
113 }
114 static inline int pthread_mutex_lock(pthread_mutex_t *m)
115 {
116  EnterCriticalSection(m);
117  return 0;
118 }
120 {
121  LeaveCriticalSection(m);
122  return 0;
123 }
124 
125 /* for pre-Windows 6.0 platforms we need to define and use our own condition
126  * variable and api */
127 typedef struct win32_cond_t {
130  volatile int waiter_count;
131  HANDLE semaphore;
132  HANDLE waiters_done;
133  volatile int is_broadcast;
134 } win32_cond_t;
135 
136 static void pthread_cond_init(pthread_cond_t *cond, const void *unused_attr)
137 {
138  win32_cond_t *win32_cond = NULL;
139  if (cond_init) {
140  cond_init(cond);
141  return;
142  }
143 
144  /* non native condition variables */
145  win32_cond = av_mallocz(sizeof(win32_cond_t));
146  if (!win32_cond)
147  return;
148  cond->ptr = win32_cond;
149  win32_cond->semaphore = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
150  if (!win32_cond->semaphore)
151  return;
152  win32_cond->waiters_done = CreateEvent(NULL, TRUE, FALSE, NULL);
153  if (!win32_cond->waiters_done)
154  return;
155 
157  pthread_mutex_init(&win32_cond->mtx_broadcast, NULL);
158 }
159 
161 {
162  win32_cond_t *win32_cond = cond->ptr;
163  /* native condition variables do not destroy */
164  if (cond_init)
165  return;
166 
167  /* non native condition variables */
168  CloseHandle(win32_cond->semaphore);
169  CloseHandle(win32_cond->waiters_done);
171  pthread_mutex_destroy(&win32_cond->mtx_broadcast);
172  av_freep(&win32_cond);
173  cond->ptr = NULL;
174 }
175 
177 {
178  win32_cond_t *win32_cond = cond->ptr;
179  int have_waiter;
180 
181  if (cond_broadcast) {
182  cond_broadcast(cond);
183  return;
184  }
185 
186  /* non native condition variables */
187  pthread_mutex_lock(&win32_cond->mtx_broadcast);
188  pthread_mutex_lock(&win32_cond->mtx_waiter_count);
189  have_waiter = 0;
190 
191  if (win32_cond->waiter_count) {
192  win32_cond->is_broadcast = 1;
193  have_waiter = 1;
194  }
195 
196  if (have_waiter) {
197  ReleaseSemaphore(win32_cond->semaphore, win32_cond->waiter_count, NULL);
199  WaitForSingleObject(win32_cond->waiters_done, INFINITE);
200  ResetEvent(win32_cond->waiters_done);
201  win32_cond->is_broadcast = 0;
202  } else
204  pthread_mutex_unlock(&win32_cond->mtx_broadcast);
205 }
206 
208 {
209  win32_cond_t *win32_cond = cond->ptr;
210  int last_waiter;
211  if (cond_wait) {
212  cond_wait(cond, mutex, INFINITE);
213  return 0;
214  }
215 
216  /* non native condition variables */
217  pthread_mutex_lock(&win32_cond->mtx_broadcast);
218  pthread_mutex_lock(&win32_cond->mtx_waiter_count);
219  win32_cond->waiter_count++;
221  pthread_mutex_unlock(&win32_cond->mtx_broadcast);
222 
223  // unlock the external mutex
224  pthread_mutex_unlock(mutex);
225  WaitForSingleObject(win32_cond->semaphore, INFINITE);
226 
227  pthread_mutex_lock(&win32_cond->mtx_waiter_count);
228  win32_cond->waiter_count--;
229  last_waiter = !win32_cond->waiter_count || !win32_cond->is_broadcast;
231 
232  if (last_waiter)
233  SetEvent(win32_cond->waiters_done);
234 
235  // lock the external mutex
236  return pthread_mutex_lock(mutex);
237 }
238 
240 {
241  win32_cond_t *win32_cond = cond->ptr;
242  int have_waiter;
243  if (cond_signal) {
244  cond_signal(cond);
245  return;
246  }
247 
248  pthread_mutex_lock(&win32_cond->mtx_broadcast);
249 
250  /* non-native condition variables */
251  pthread_mutex_lock(&win32_cond->mtx_waiter_count);
252  have_waiter = win32_cond->waiter_count;
254 
255  if (have_waiter) {
256  ReleaseSemaphore(win32_cond->semaphore, 1, NULL);
257  WaitForSingleObject(win32_cond->waiters_done, INFINITE);
258  ResetEvent(win32_cond->waiters_done);
259  }
260 
261  pthread_mutex_unlock(&win32_cond->mtx_broadcast);
262 }
263 
264 static void w32thread_init(void)
265 {
266 #if _WIN32_WINNT < 0x0600
267  HANDLE kernel_dll = GetModuleHandle(TEXT("kernel32.dll"));
268  /* if one is available, then they should all be available */
269  cond_init =
270  (void*)GetProcAddress(kernel_dll, "InitializeConditionVariable");
271  cond_broadcast =
272  (void*)GetProcAddress(kernel_dll, "WakeAllConditionVariable");
273  cond_signal =
274  (void*)GetProcAddress(kernel_dll, "WakeConditionVariable");
275  cond_wait =
276  (void*)GetProcAddress(kernel_dll, "SleepConditionVariableCS");
277 #endif
278 
279 }
280 
281 #endif /* LIBAV_COMPAT_W32PTHREADS_H */