Clean up the Chorus a little
[openal-soft.git] / common / threads.cpp
blob7d44c0127a84f1e0f4345a6485c503fed6fd11da
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include "threads.h"
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
29 #include "uintmap.h"
32 #ifndef UNUSED
33 #if defined(__cplusplus)
34 #define UNUSED(x)
35 #elif defined(__GNUC__)
36 #define UNUSED(x) UNUSED_##x __attribute__((unused))
37 #elif defined(__LCLINT__)
38 #define UNUSED(x) /*@unused@*/ x
39 #else
40 #define UNUSED(x) x
41 #endif
42 #endif
45 #define THREAD_STACK_SIZE (2*1024*1024) /* 2MB */
47 #ifdef _WIN32
49 #define WIN32_LEAN_AND_MEAN
50 #include <windows.h>
51 #include <mmsystem.h>
54 /* An associative map of uint:void* pairs. The key is the unique Thread ID and
55 * the value is the thread HANDLE. The thread ID is passed around as the
56 * althrd_t since there is only one ID per thread, whereas a thread may be
57 * referenced by multiple different HANDLEs. This map allows retrieving the
58 * original handle which is needed to join the thread and get its return value.
60 static ThrSafeMap<DWORD,HANDLE> ThrdIdHandle{};
63 void althrd_setname(const char *name)
65 #if defined(_MSC_VER)
66 #define MS_VC_EXCEPTION 0x406D1388
67 #pragma pack(push,8)
68 struct {
69 DWORD dwType; // Must be 0x1000.
70 LPCSTR szName; // Pointer to name (in user addr space).
71 DWORD dwThreadID; // Thread ID (-1=caller thread).
72 DWORD dwFlags; // Reserved for future use, must be zero.
73 } info;
74 #pragma pack(pop)
75 info.dwType = 0x1000;
76 info.szName = name;
77 info.dwThreadID = -1;
78 info.dwFlags = 0;
80 __try {
81 RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
83 __except(EXCEPTION_CONTINUE_EXECUTION) {
85 #undef MS_VC_EXCEPTION
86 #else
87 (void)name;
88 #endif
92 typedef struct thread_cntr {
93 althrd_start_t func;
94 void *arg;
95 } thread_cntr;
97 static DWORD WINAPI althrd_starter(void *arg)
99 thread_cntr cntr;
100 memcpy(&cntr, arg, sizeof(cntr));
101 free(arg);
103 return (DWORD)((*cntr.func)(cntr.arg));
107 int althrd_create(althrd_t *thr, althrd_start_t func, void *arg)
109 thread_cntr *cntr;
110 DWORD thrid;
111 HANDLE hdl;
113 cntr = static_cast<thread_cntr*>(malloc(sizeof(*cntr)));
114 if(!cntr) return althrd_nomem;
116 cntr->func = func;
117 cntr->arg = arg;
119 hdl = CreateThread(NULL, THREAD_STACK_SIZE, althrd_starter, cntr, 0, &thrid);
120 if(!hdl)
122 free(cntr);
123 return althrd_error;
125 ThrdIdHandle.InsertEntry(thrid, hdl);
127 *thr = thrid;
128 return althrd_success;
131 int althrd_detach(althrd_t thr)
133 HANDLE hdl = ThrdIdHandle.RemoveKey(thr);
134 if(!hdl) return althrd_error;
136 CloseHandle(hdl);
137 return althrd_success;
140 int althrd_join(althrd_t thr, int *res)
142 DWORD code;
144 HANDLE hdl = ThrdIdHandle.RemoveKey(thr);
145 if(!hdl) return althrd_error;
147 WaitForSingleObject(hdl, INFINITE);
148 GetExitCodeThread(hdl, &code);
149 CloseHandle(hdl);
151 if(res != NULL)
152 *res = (int)code;
153 return althrd_success;
157 int almtx_init(almtx_t *mtx, int type)
159 if(!mtx) return althrd_error;
161 type &= ~almtx_recursive;
162 if(type != almtx_plain)
163 return althrd_error;
165 InitializeCriticalSection(mtx);
166 return althrd_success;
169 void almtx_destroy(almtx_t *mtx)
171 DeleteCriticalSection(mtx);
175 int alsem_init(alsem_t *sem, unsigned int initial)
177 *sem = CreateSemaphore(NULL, initial, INT_MAX, NULL);
178 if(*sem != NULL) return althrd_success;
179 return althrd_error;
182 void alsem_destroy(alsem_t *sem)
184 CloseHandle(*sem);
187 int alsem_post(alsem_t *sem)
189 DWORD ret = ReleaseSemaphore(*sem, 1, NULL);
190 if(ret) return althrd_success;
191 return althrd_error;
194 int alsem_wait(alsem_t *sem)
196 DWORD ret = WaitForSingleObject(*sem, INFINITE);
197 if(ret == WAIT_OBJECT_0) return althrd_success;
198 return althrd_error;
201 int alsem_trywait(alsem_t *sem)
203 DWORD ret = WaitForSingleObject(*sem, 0);
204 if(ret == WAIT_OBJECT_0) return althrd_success;
205 if(ret == WAIT_TIMEOUT) return althrd_busy;
206 return althrd_error;
209 #else
211 #include <sys/time.h>
212 #include <unistd.h>
213 #include <pthread.h>
214 #ifdef HAVE_PTHREAD_NP_H
215 #include <pthread_np.h>
216 #endif
219 void althrd_setname(const char *name)
221 #if defined(HAVE_PTHREAD_SETNAME_NP)
222 #if defined(PTHREAD_SETNAME_NP_ONE_PARAM)
223 pthread_setname_np(name);
224 #elif defined(PTHREAD_SETNAME_NP_THREE_PARAMS)
225 pthread_setname_np(pthread_self(), "%s", (void*)name);
226 #else
227 pthread_setname_np(pthread_self(), name);
228 #endif
229 #elif defined(HAVE_PTHREAD_SET_NAME_NP)
230 pthread_set_name_np(pthread_self(), name);
231 #else
232 (void)name;
233 #endif
237 typedef struct thread_cntr {
238 althrd_start_t func;
239 void *arg;
240 } thread_cntr;
242 static void *althrd_starter(void *arg)
244 thread_cntr cntr;
245 memcpy(&cntr, arg, sizeof(cntr));
246 free(arg);
248 return (void*)(intptr_t)((*cntr.func)(cntr.arg));
252 int althrd_create(althrd_t *thr, althrd_start_t func, void *arg)
254 thread_cntr *cntr;
255 pthread_attr_t attr;
256 size_t stackmult = 1;
257 int err;
259 cntr = static_cast<thread_cntr*>(malloc(sizeof(*cntr)));
260 if(!cntr) return althrd_nomem;
262 if(pthread_attr_init(&attr) != 0)
264 free(cntr);
265 return althrd_error;
267 retry_stacksize:
268 if(pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE*stackmult) != 0)
270 pthread_attr_destroy(&attr);
271 free(cntr);
272 return althrd_error;
275 cntr->func = func;
276 cntr->arg = arg;
277 if((err=pthread_create(thr, &attr, althrd_starter, cntr)) == 0)
279 pthread_attr_destroy(&attr);
280 return althrd_success;
283 if(err == EINVAL)
285 /* If an invalid stack size, try increasing it (limit x4, 8MB). */
286 if(stackmult < 4)
288 stackmult *= 2;
289 goto retry_stacksize;
291 /* If still nothing, try defaults and hope they're good enough. */
292 if(pthread_create(thr, NULL, althrd_starter, cntr) == 0)
294 pthread_attr_destroy(&attr);
295 return althrd_success;
298 pthread_attr_destroy(&attr);
299 free(cntr);
300 return althrd_error;
303 int althrd_detach(althrd_t thr)
305 if(pthread_detach(thr) != 0)
306 return althrd_error;
307 return althrd_success;
310 int althrd_join(althrd_t thr, int *res)
312 void *code;
314 if(pthread_join(thr, &code) != 0)
315 return althrd_error;
316 if(res != NULL)
317 *res = (int)(intptr_t)code;
318 return althrd_success;
322 int almtx_init(almtx_t *mtx, int type)
324 int ret;
326 if(!mtx) return althrd_error;
327 if((type&~almtx_recursive) != 0)
328 return althrd_error;
330 if(type == almtx_plain)
331 ret = pthread_mutex_init(mtx, NULL);
332 else
334 pthread_mutexattr_t attr;
336 ret = pthread_mutexattr_init(&attr);
337 if(ret) return althrd_error;
339 if(type == almtx_recursive)
341 ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
342 #ifdef HAVE_PTHREAD_MUTEXATTR_SETKIND_NP
343 if(ret != 0)
344 ret = pthread_mutexattr_setkind_np(&attr, PTHREAD_MUTEX_RECURSIVE);
345 #endif
347 else
348 ret = 1;
349 if(ret == 0)
350 ret = pthread_mutex_init(mtx, &attr);
351 pthread_mutexattr_destroy(&attr);
353 return ret ? althrd_error : althrd_success;
356 void almtx_destroy(almtx_t *mtx)
358 pthread_mutex_destroy(mtx);
362 #ifdef __APPLE__
364 int alsem_init(alsem_t *sem, unsigned int initial)
366 *sem = dispatch_semaphore_create(initial);
367 return *sem ? althrd_success : althrd_error;
370 void alsem_destroy(alsem_t *sem)
372 dispatch_release(*sem);
375 int alsem_post(alsem_t *sem)
377 dispatch_semaphore_signal(*sem);
378 return althrd_success;
381 int alsem_wait(alsem_t *sem)
383 dispatch_semaphore_wait(*sem, DISPATCH_TIME_FOREVER);
384 return althrd_success;
387 int alsem_trywait(alsem_t *sem)
389 long value = dispatch_semaphore_wait(*sem, DISPATCH_TIME_NOW);
390 return value == 0 ? althrd_success : althrd_busy;
393 #else /* !__APPLE__ */
395 int alsem_init(alsem_t *sem, unsigned int initial)
397 if(sem_init(sem, 0, initial) == 0)
398 return althrd_success;
399 return althrd_error;
402 void alsem_destroy(alsem_t *sem)
404 sem_destroy(sem);
407 int alsem_post(alsem_t *sem)
409 if(sem_post(sem) == 0)
410 return althrd_success;
411 return althrd_error;
414 int alsem_wait(alsem_t *sem)
416 if(sem_wait(sem) == 0) return althrd_success;
417 if(errno == EINTR) return -2;
418 return althrd_error;
421 int alsem_trywait(alsem_t *sem)
423 if(sem_trywait(sem) == 0) return althrd_success;
424 if(errno == EWOULDBLOCK) return althrd_busy;
425 if(errno == EINTR) return -2;
426 return althrd_error;
429 #endif /* __APPLE__ */
431 #endif