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
33 #if defined(__cplusplus)
35 #elif defined(__GNUC__)
36 #define UNUSED(x) UNUSED_##x __attribute__((unused))
37 #elif defined(__LCLINT__)
38 #define UNUSED(x) /*@unused@*/ x
45 #define THREAD_STACK_SIZE (2*1024*1024) /* 2MB */
49 #define WIN32_LEAN_AND_MEAN
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
)
66 #define MS_VC_EXCEPTION 0x406D1388
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.
81 RaiseException(MS_VC_EXCEPTION
, 0, sizeof(info
)/sizeof(ULONG_PTR
), (ULONG_PTR
*)&info
);
83 __except(EXCEPTION_CONTINUE_EXECUTION
) {
85 #undef MS_VC_EXCEPTION
92 typedef struct thread_cntr
{
97 static DWORD WINAPI
althrd_starter(void *arg
)
100 memcpy(&cntr
, arg
, sizeof(cntr
));
103 return (DWORD
)((*cntr
.func
)(cntr
.arg
));
107 int althrd_create(althrd_t
*thr
, althrd_start_t func
, void *arg
)
113 cntr
= static_cast<thread_cntr
*>(malloc(sizeof(*cntr
)));
114 if(!cntr
) return althrd_nomem
;
119 hdl
= CreateThread(NULL
, THREAD_STACK_SIZE
, althrd_starter
, cntr
, 0, &thrid
);
125 ThrdIdHandle
.InsertEntry(thrid
, hdl
);
128 return althrd_success
;
131 int althrd_detach(althrd_t thr
)
133 HANDLE hdl
= ThrdIdHandle
.RemoveKey(thr
);
134 if(!hdl
) return althrd_error
;
137 return althrd_success
;
140 int althrd_join(althrd_t thr
, int *res
)
144 HANDLE hdl
= ThrdIdHandle
.RemoveKey(thr
);
145 if(!hdl
) return althrd_error
;
147 WaitForSingleObject(hdl
, INFINITE
);
148 GetExitCodeThread(hdl
, &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
)
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
;
182 void alsem_destroy(alsem_t
*sem
)
187 int alsem_post(alsem_t
*sem
)
189 DWORD ret
= ReleaseSemaphore(*sem
, 1, NULL
);
190 if(ret
) return althrd_success
;
194 int alsem_wait(alsem_t
*sem
)
196 DWORD ret
= WaitForSingleObject(*sem
, INFINITE
);
197 if(ret
== WAIT_OBJECT_0
) return althrd_success
;
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
;
211 #include <sys/time.h>
214 #ifdef HAVE_PTHREAD_NP_H
215 #include <pthread_np.h>
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
);
227 pthread_setname_np(pthread_self(), name
);
229 #elif defined(HAVE_PTHREAD_SET_NAME_NP)
230 pthread_set_name_np(pthread_self(), name
);
237 typedef struct thread_cntr
{
242 static void *althrd_starter(void *arg
)
245 memcpy(&cntr
, arg
, sizeof(cntr
));
248 return (void*)(intptr_t)((*cntr
.func
)(cntr
.arg
));
252 int althrd_create(althrd_t
*thr
, althrd_start_t func
, void *arg
)
256 size_t stackmult
= 1;
259 cntr
= static_cast<thread_cntr
*>(malloc(sizeof(*cntr
)));
260 if(!cntr
) return althrd_nomem
;
262 if(pthread_attr_init(&attr
) != 0)
268 if(pthread_attr_setstacksize(&attr
, THREAD_STACK_SIZE
*stackmult
) != 0)
270 pthread_attr_destroy(&attr
);
277 if((err
=pthread_create(thr
, &attr
, althrd_starter
, cntr
)) == 0)
279 pthread_attr_destroy(&attr
);
280 return althrd_success
;
285 /* If an invalid stack size, try increasing it (limit x4, 8MB). */
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
);
303 int althrd_detach(althrd_t thr
)
305 if(pthread_detach(thr
) != 0)
307 return althrd_success
;
310 int althrd_join(althrd_t thr
, int *res
)
314 if(pthread_join(thr
, &code
) != 0)
317 *res
= (int)(intptr_t)code
;
318 return althrd_success
;
322 int almtx_init(almtx_t
*mtx
, int type
)
326 if(!mtx
) return althrd_error
;
327 if((type
&~almtx_recursive
) != 0)
330 if(type
== almtx_plain
)
331 ret
= pthread_mutex_init(mtx
, NULL
);
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
344 ret
= pthread_mutexattr_setkind_np(&attr
, PTHREAD_MUTEX_RECURSIVE
);
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
);
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
;
402 void alsem_destroy(alsem_t
*sem
)
407 int alsem_post(alsem_t
*sem
)
409 if(sem_post(sem
) == 0)
410 return althrd_success
;
414 int alsem_wait(alsem_t
*sem
)
416 if(sem_wait(sem
) == 0) return althrd_success
;
417 if(errno
== EINTR
) return -2;
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;
429 #endif /* __APPLE__ */