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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
32 extern inline althrd_t
althrd_current(void);
33 extern inline int althrd_equal(althrd_t thr0
, althrd_t thr1
);
34 extern inline void althrd_exit(int res
);
35 extern inline void althrd_yield(void);
37 extern inline int almtx_lock(almtx_t
*mtx
);
38 extern inline int almtx_unlock(almtx_t
*mtx
);
39 extern inline int almtx_trylock(almtx_t
*mtx
);
41 extern inline void *altss_get(altss_t tss_id
);
42 extern inline int altss_set(altss_t tss_id
, void *val
);
46 #if defined(__cplusplus)
48 #elif defined(__GNUC__)
49 #define UNUSED(x) UNUSED_##x __attribute__((unused))
50 #elif defined(__LCLINT__)
51 #define UNUSED(x) /*@unused@*/ x
58 #define THREAD_STACK_SIZE (1*1024*1024) /* 1MB */
62 #define WIN32_LEAN_AND_MEAN
67 void althrd_setname(althrd_t thr
, const char *name
)
70 #define MS_VC_EXCEPTION 0x406D1388
73 DWORD dwType
; // Must be 0x1000.
74 LPCSTR szName
; // Pointer to name (in user addr space).
75 DWORD dwThreadID
; // Thread ID (-1=caller thread).
76 DWORD dwFlags
; // Reserved for future use, must be zero.
81 info
.dwThreadID
= thr
;
85 RaiseException(MS_VC_EXCEPTION
, 0, sizeof(info
)/sizeof(ULONG_PTR
), (ULONG_PTR
*)&info
);
87 __except(EXCEPTION_CONTINUE_EXECUTION
) {
89 #undef MS_VC_EXCEPTION
97 static UIntMap ThrdIdHandle
= UINTMAP_STATIC_INITIALIZE
;
99 static void NTAPI
althrd_callback(void* UNUSED(handle
), DWORD reason
, void* UNUSED(reserved
))
101 if(reason
== DLL_PROCESS_DETACH
)
102 ResetUIntMap(&ThrdIdHandle
);
105 #pragma section(".CRT$XLC",read)
106 __declspec(allocate(".CRT$XLC")) PIMAGE_TLS_CALLBACK althrd_callback_
= althrd_callback
;
107 #elif defined(__GNUC__)
108 PIMAGE_TLS_CALLBACK althrd_callback_
__attribute__((section(".CRT$XLC"))) = althrd_callback
;
110 PIMAGE_TLS_CALLBACK althrd_callback_
= althrd_callback
;
114 typedef struct thread_cntr
{
119 static DWORD WINAPI
althrd_starter(void *arg
)
122 memcpy(&cntr
, arg
, sizeof(cntr
));
125 return (DWORD
)((*cntr
.func
)(cntr
.arg
));
129 int althrd_create(althrd_t
*thr
, althrd_start_t func
, void *arg
)
135 cntr
= malloc(sizeof(*cntr
));
136 if(!cntr
) return althrd_nomem
;
141 hdl
= CreateThread(NULL
, THREAD_STACK_SIZE
, althrd_starter
, cntr
, 0, &thrid
);
147 InsertUIntMapEntry(&ThrdIdHandle
, thrid
, hdl
);
150 return althrd_success
;
153 int althrd_detach(althrd_t thr
)
155 HANDLE hdl
= RemoveUIntMapKey(&ThrdIdHandle
, thr
);
156 if(!hdl
) return althrd_error
;
159 return althrd_success
;
162 int althrd_join(althrd_t thr
, int *res
)
166 HANDLE hdl
= RemoveUIntMapKey(&ThrdIdHandle
, thr
);
167 if(!hdl
) return althrd_error
;
169 WaitForSingleObject(hdl
, INFINITE
);
170 GetExitCodeThread(hdl
, &code
);
174 return althrd_success
;
177 int althrd_sleep(const struct timespec
*ts
, struct timespec
* UNUSED(rem
))
181 if(ts
->tv_sec
< 0 || ts
->tv_sec
>= (0x7fffffff / 1000) ||
182 ts
->tv_nsec
< 0 || ts
->tv_nsec
>= 1000000000)
185 msec
= (DWORD
)(ts
->tv_sec
* 1000);
186 msec
+= (DWORD
)((ts
->tv_nsec
+999999) / 1000000);
193 int almtx_init(almtx_t
*mtx
, int type
)
195 if(!mtx
) return althrd_error
;
196 type
&= ~(almtx_recursive
|almtx_timed
);
197 if(type
!= almtx_plain
)
200 InitializeCriticalSection(mtx
);
201 return althrd_success
;
204 void almtx_destroy(almtx_t
*mtx
)
206 DeleteCriticalSection(mtx
);
209 int almtx_timedlock(almtx_t
*mtx
, const struct timespec
*ts
)
216 while((ret
=almtx_trylock(mtx
)) == althrd_busy
)
220 if(ts
->tv_sec
< 0 || ts
->tv_nsec
< 0 || ts
->tv_nsec
>= 1000000000 ||
221 altimespec_get(&now
, AL_TIME_UTC
) != AL_TIME_UTC
)
223 if(now
.tv_sec
> ts
->tv_sec
|| (now
.tv_sec
== ts
->tv_sec
&& now
.tv_nsec
>= ts
->tv_nsec
))
224 return althrd_timedout
;
233 /* An associative map of uint:void* pairs. The key is the TLS index (given by
234 * TlsAlloc), and the value is the altss_dtor_t callback. When a thread exits,
235 * we iterate over the TLS indices for their thread-local value and call the
236 * destructor function with it if they're both not NULL. To avoid using
237 * DllMain, a PIMAGE_TLS_CALLBACK function pointer is placed in a ".CRT$XLx"
238 * section (where x is a character A to Z) which will be called by the CRT.
240 static UIntMap TlsDestructors
= UINTMAP_STATIC_INITIALIZE
;
242 static void NTAPI
altss_callback(void* UNUSED(handle
), DWORD reason
, void* UNUSED(reserved
))
246 if(reason
== DLL_PROCESS_DETACH
)
248 ResetUIntMap(&TlsDestructors
);
251 if(reason
!= DLL_THREAD_DETACH
)
254 LockUIntMapRead(&TlsDestructors
);
255 for(i
= 0;i
< TlsDestructors
.size
;i
++)
257 void *ptr
= altss_get(TlsDestructors
.array
[i
].key
);
258 altss_dtor_t callback
= (altss_dtor_t
)TlsDestructors
.array
[i
].value
;
262 UnlockUIntMapRead(&TlsDestructors
);
265 #pragma section(".CRT$XLB",read)
266 __declspec(allocate(".CRT$XLB")) PIMAGE_TLS_CALLBACK altss_callback_
= altss_callback
;
267 #elif defined(__GNUC__)
268 PIMAGE_TLS_CALLBACK altss_callback_
__attribute__((section(".CRT$XLB"))) = altss_callback
;
270 #warning "No TLS callback support, thread-local contexts may leak references on poorly written applications."
271 PIMAGE_TLS_CALLBACK altss_callback_
= altss_callback
;
274 int altss_create(altss_t
*tss_id
, altss_dtor_t callback
)
276 DWORD key
= TlsAlloc();
277 if(key
== TLS_OUT_OF_INDEXES
)
282 InsertUIntMapEntry(&TlsDestructors
, key
, callback
);
283 return althrd_success
;
286 void altss_delete(altss_t tss_id
)
288 RemoveUIntMapKey(&TlsDestructors
, tss_id
);
293 int altimespec_get(struct timespec
*ts
, int base
)
295 if(base
== AL_TIME_UTC
)
299 ULARGE_INTEGER ulint
;
301 GetSystemTimeAsFileTime(&systime
.ftime
);
302 /* FILETIME is in 100-nanosecond units, or 1/10th of a microsecond. */
303 ts
->tv_sec
= systime
.ulint
.QuadPart
/10000000;
304 ts
->tv_nsec
= (systime
.ulint
.QuadPart
%10000000) * 100;
312 void alcall_once(alonce_flag
*once
, void (*callback
)(void))
315 while((ret
=InterlockedExchange(once
, 1)) == 1)
319 InterlockedExchange(once
, 2);
324 #include <sys/time.h>
327 #ifdef HAVE_PTHREAD_NP_H
328 #include <pthread_np.h>
332 extern inline int althrd_sleep(const struct timespec
*ts
, struct timespec
*rem
);
333 extern inline void alcall_once(alonce_flag
*once
, void (*callback
)(void));
336 void althrd_setname(althrd_t thr
, const char *name
)
338 #if defined(HAVE_PTHREAD_SETNAME_NP)
339 #if defined(__GNUC__)
340 pthread_setname_np(thr
, name
);
341 #elif defined(__APPLE__)
342 if(althrd_equal(thr
, althrd_current())
343 pthread_setname_np(name
);
345 #elif defined(HAVE_PTHREAD_SET_NAME_NP)
346 pthread_set_name_np(thr
, name
);
354 typedef struct thread_cntr
{
359 static void *althrd_starter(void *arg
)
362 memcpy(&cntr
, arg
, sizeof(cntr
));
365 return (void*)(intptr_t)((*cntr
.func
)(cntr
.arg
));
369 int althrd_create(althrd_t
*thr
, althrd_start_t func
, void *arg
)
374 cntr
= malloc(sizeof(*cntr
));
375 if(!cntr
) return althrd_nomem
;
377 if(pthread_attr_init(&attr
) != 0)
382 if(pthread_attr_setstacksize(&attr
, THREAD_STACK_SIZE
) != 0)
384 pthread_attr_destroy(&attr
);
391 if(pthread_create(thr
, &attr
, althrd_starter
, cntr
) != 0)
393 pthread_attr_destroy(&attr
);
397 pthread_attr_destroy(&attr
);
399 return althrd_success
;
402 int althrd_detach(althrd_t thr
)
404 if(pthread_detach(thr
) != 0)
406 return althrd_success
;
409 int althrd_join(althrd_t thr
, int *res
)
413 if(!res
) return althrd_error
;
415 if(pthread_join(thr
, &code
) != 0)
417 *res
= (int)(intptr_t)code
;
418 return althrd_success
;
422 int almtx_init(almtx_t
*mtx
, int type
)
426 if(!mtx
) return althrd_error
;
427 if((type
&~(almtx_recursive
|almtx_timed
)) != 0)
430 type
&= ~almtx_timed
;
431 if(type
== almtx_plain
)
432 ret
= pthread_mutex_init(mtx
, NULL
);
435 pthread_mutexattr_t attr
;
437 ret
= pthread_mutexattr_init(&attr
);
438 if(ret
) return althrd_error
;
440 if(type
== almtx_recursive
)
442 ret
= pthread_mutexattr_settype(&attr
, PTHREAD_MUTEX_RECURSIVE
);
443 #ifdef HAVE_PTHREAD_MUTEXATTR_SETKIND_NP
445 ret
= pthread_mutexattr_setkind_np(&attr
, PTHREAD_MUTEX_RECURSIVE
);
451 ret
= pthread_mutex_init(mtx
, &attr
);
452 pthread_mutexattr_destroy(&attr
);
454 return ret
? althrd_error
: althrd_success
;
457 void almtx_destroy(almtx_t
*mtx
)
459 pthread_mutex_destroy(mtx
);
462 int almtx_timedlock(almtx_t
*mtx
, const struct timespec
*ts
)
466 #ifdef HAVE_PTHREAD_MUTEX_TIMEDLOCK
467 ret
= pthread_mutex_timedlock(mtx
, ts
);
470 case 0: return althrd_success
;
471 case ETIMEDOUT
: return althrd_timedout
;
472 case EBUSY
: return althrd_busy
;
479 while((ret
=almtx_trylock(mtx
)) == althrd_busy
)
483 if(ts
->tv_sec
< 0 || ts
->tv_nsec
< 0 || ts
->tv_nsec
>= 1000000000 ||
484 altimespec_get(&now
, AL_TIME_UTC
) != AL_TIME_UTC
)
486 if(now
.tv_sec
> ts
->tv_sec
|| (now
.tv_sec
== ts
->tv_sec
&& now
.tv_nsec
>= ts
->tv_nsec
))
487 return althrd_timedout
;
497 int altss_create(altss_t
*tss_id
, altss_dtor_t callback
)
499 if(pthread_key_create(tss_id
, callback
) != 0)
501 return althrd_success
;
504 void altss_delete(altss_t tss_id
)
506 pthread_key_delete(tss_id
);
510 int altimespec_get(struct timespec
*ts
, int base
)
512 if(base
== AL_TIME_UTC
)
515 #if _POSIX_TIMERS > 0
516 ret
= clock_gettime(CLOCK_REALTIME
, ts
);
517 if(ret
== 0) return base
;
518 #else /* _POSIX_TIMERS > 0 */
520 ret
= gettimeofday(&tv
, NULL
);
523 ts
->tv_sec
= tv
.tv_sec
;
524 ts
->tv_nsec
= tv
.tv_usec
* 1000;
536 void al_nssleep(time_t sec
, long nsec
)
538 struct timespec ts
, rem
;
542 while(althrd_sleep(&ts
, &rem
) == -1)