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 int althrd_equal(althrd_t thr0
, althrd_t thr1
);
33 extern inline void althrd_exit(int res
);
34 extern inline void althrd_yield(void);
36 extern inline int almtx_lock(almtx_t
*mtx
);
37 extern inline int almtx_unlock(almtx_t
*mtx
);
38 extern inline int almtx_trylock(almtx_t
*mtx
);
40 extern inline void *altss_get(altss_t tss_id
);
41 extern inline int altss_set(altss_t tss_id
, void *val
);
43 extern inline void al_nssleep(time_t sec
, long nsec
);
46 #define THREAD_STACK_SIZE (1*1024*1024) /* 1MB */
50 #define WIN32_LEAN_AND_MEAN
55 void SetThreadName(const char *name
)
58 #define MS_VC_EXCEPTION 0x406D1388
60 DWORD dwType
; // Must be 0x1000.
61 LPCSTR szName
; // Pointer to name (in user addr space).
62 DWORD dwThreadID
; // Thread ID (-1=caller thread).
63 DWORD dwFlags
; // Reserved for future use, must be zero.
71 RaiseException(MS_VC_EXCEPTION
, 0, sizeof(info
)/sizeof(DWORD
), (ULONG_PTR
*)&info
);
73 __except(EXCEPTION_CONTINUE_EXECUTION
) {
75 #undef MS_VC_EXCEPTION
77 TRACE("Can't set thread %04lx name to \"%s\"\n", GetCurrentThreadId(), name
);
82 typedef struct thread_cntr
{
87 static DWORD WINAPI
althrd_starter(void *arg
)
90 memcpy(&cntr
, arg
, sizeof(cntr
));
93 return (DWORD
)((*cntr
.func
)(cntr
.arg
));
97 int althrd_create(althrd_t
*thr
, althrd_start_t func
, void *arg
)
103 cntr
= malloc(sizeof(*cntr
));
104 if(!cntr
) return althrd_nomem
;
109 hdl
= CreateThread(NULL
, THREAD_STACK_SIZE
, althrd_starter
, cntr
, 0, &dummy
);
117 return althrd_success
;
120 int althrd_detach(althrd_t thr
)
122 if(!thr
) return althrd_error
;
125 return althrd_success
;
128 int althrd_join(althrd_t thr
, int *res
)
132 if(!thr
) return althrd_error
;
134 WaitForSingleObject(thr
, INFINITE
);
135 GetExitCodeThread(thr
, &code
);
139 return althrd_success
;
142 int althrd_sleep(const struct timespec
*ts
, struct timespec
* UNUSED(rem
))
146 if(ts
->tv_sec
< 0 || ts
->tv_sec
>= (0xffffffffu
/ 1000) ||
147 ts
->tv_nsec
< 0 || ts
->tv_nsec
>= 1000000000)
150 msec
= (DWORD
)(ts
->tv_sec
* 1000);
151 msec
+= (DWORD
)((ts
->tv_nsec
+999999) / 1000000);
158 int almtx_init(almtx_t
*mtx
, int type
)
160 if(!mtx
) return althrd_error
;
161 type
&= ~(almtx_recursive
|almtx_timed
);
162 if(type
!= almtx_plain
)
165 InitializeCriticalSection(mtx
);
166 return althrd_success
;
169 void almtx_destroy(almtx_t
*mtx
)
171 DeleteCriticalSection(mtx
);
174 int almtx_timedlock(almtx_t
*mtx
, const struct timespec
*ts
)
176 DWORD start
, timelen
;
182 timelen
= ts
->tv_sec
* 1000;
183 timelen
+= (ts
->tv_nsec
+999999) / 1000000;
185 start
= timeGetTime();
186 while((ret
=almtx_trylock(mtx
)) == althrd_busy
)
188 DWORD now
= timeGetTime();
189 if(now
-start
>= timelen
)
191 ret
= althrd_timedout
;
201 /* An associative map of uint:void* pairs. The key is the TLS index (given by
202 * TlsAlloc), and the value is the altss_dtor_t callback. When a thread exits,
203 * it iterates over the thread-local value for each TLS key and calls the
204 * destructor function if they're both not NULL. Placing a PIMAGE_TLS_CALLBACK
205 * function pointer in a ".CRT$XLx" section (where x is a character A to Z)
206 * ensures the CRT will call it similar to DllMain.
208 static UIntMap TlsDestructors
= UINTMAP_STATIC_INITIALIZE
;
210 static void NTAPI
altss_callback(void* UNUSED(handle
), DWORD reason
, void* UNUSED(reserved
))
214 if(reason
== DLL_PROCESS_DETACH
)
216 ResetUIntMap(&TlsDestructors
);
219 if(reason
!= DLL_THREAD_DETACH
)
222 LockUIntMapRead(&TlsDestructors
);
223 for(i
= 0;i
< TlsDestructors
.size
;i
++)
225 void *ptr
= altss_get(TlsDestructors
.array
[i
].key
);
226 altss_dtor_t callback
= (altss_dtor_t
)TlsDestructors
.array
[i
].value
;
230 UnlockUIntMapRead(&TlsDestructors
);
233 #pragma section(".CRT$XLB",read)
234 __declspec(allocate(".CRT$XLB")) PIMAGE_TLS_CALLBACK altss_callback_
= altss_callback
;
235 #elif defined(__GNUC__)
236 PIMAGE_TLS_CALLBACK altss_callback_
__attribute__((section(".CRT$XLB"))) = altss_callback
;
238 #warning "No TLS callback support, thread-local contexts may leak references on poorly written applications."
239 PIMAGE_TLS_CALLBACK altss_callback_
= altss_callback
;
242 int altss_create(altss_t
*tss_id
, altss_dtor_t callback
)
244 DWORD key
= TlsAlloc();
245 if(key
== TLS_OUT_OF_INDEXES
)
250 InsertUIntMapEntry(&TlsDestructors
, key
, callback
);
251 return althrd_success
;
254 void altss_delete(altss_t tss_id
)
256 RemoveUIntMapKey(&TlsDestructors
, tss_id
);
263 #ifdef HAVE_PTHREAD_NP_H
264 #include <pthread_np.h>
268 extern inline althrd_t
althrd_current(void);
269 extern inline int althrd_sleep(const struct timespec
*ts
, struct timespec
*rem
);
272 void SetThreadName(const char *name
)
274 #if defined(HAVE_PTHREAD_SETNAME_NP)
275 #if defined(__GNUC__)
276 if(pthread_setname_np(pthread_self(), name
) != 0)
277 #elif defined(__APPLE__)
278 if(pthread_setname_np(name
) != 0)
280 WARN("Failed to set thread name to \"%s\": %s\n", name
, strerror(errno
));
281 #elif defined(HAVE_PTHREAD_SET_NAME_NP)
282 pthread_set_name_np(pthread_self(), name
);
284 TRACE("Can't set thread name to \"%s\"\n", name
);
289 typedef struct thread_cntr
{
294 static void *althrd_starter(void *arg
)
297 memcpy(&cntr
, arg
, sizeof(cntr
));
300 return (void*)(intptr_t)((*cntr
.func
)(cntr
.arg
));
304 int althrd_create(althrd_t
*thr
, althrd_start_t func
, void *arg
)
309 cntr
= malloc(sizeof(*cntr
));
310 if(!cntr
) return althrd_nomem
;
312 if(pthread_attr_init(&attr
) != 0)
317 if(pthread_attr_setstacksize(&attr
, THREAD_STACK_SIZE
) != 0)
319 pthread_attr_destroy(&attr
);
326 if(pthread_create(thr
, &attr
, althrd_starter
, cntr
) != 0)
328 pthread_attr_destroy(&attr
);
332 pthread_attr_destroy(&attr
);
334 return althrd_success
;
337 int althrd_detach(althrd_t thr
)
339 if(pthread_detach(thr
) != 0)
341 return althrd_success
;
344 int althrd_join(althrd_t thr
, int *res
)
348 if(!res
) return althrd_error
;
350 if(pthread_join(thr
, &code
) != 0)
352 *res
= (int)(intptr_t)code
;
353 return althrd_success
;
357 int almtx_init(almtx_t
*mtx
, int type
)
361 if(!mtx
) return althrd_error
;
362 if((type
&~(almtx_recursive
|almtx_timed
)) != 0)
365 type
&= ~almtx_timed
;
366 if(type
== almtx_plain
)
367 ret
= pthread_mutex_init(mtx
, NULL
);
370 pthread_mutexattr_t attr
;
372 ret
= pthread_mutexattr_init(&attr
);
373 if(ret
) return althrd_error
;
375 if(type
== almtx_recursive
)
377 ret
= pthread_mutexattr_settype(&attr
, PTHREAD_MUTEX_RECURSIVE
);
378 #ifdef HAVE_PTHREAD_NP_H
380 ret
= pthread_mutexattr_setkind_np(&attr
, PTHREAD_MUTEX_RECURSIVE
);
386 ret
= pthread_mutex_init(mtx
, &attr
);
387 pthread_mutexattr_destroy(&attr
);
389 return ret
? althrd_error
: althrd_success
;
392 void almtx_destroy(almtx_t
*mtx
)
394 pthread_mutex_destroy(mtx
);
397 int almtx_timedlock(almtx_t
*mtx
, const struct timespec
*ts
)
404 ret
= pthread_mutex_timedlock(mtx
, ts
);
407 case 0: return althrd_success
;
408 case ETIMEDOUT
: return althrd_timedout
;
410 case EBUSY
: return althrd_busy
;
416 int altss_create(altss_t
*tss_id
, altss_dtor_t callback
)
418 if(pthread_key_create(tss_id
, callback
) != 0)
420 return althrd_success
;
423 void altss_delete(altss_t tss_id
)
425 pthread_key_delete(tss_id
);