programs: Get rid of the remaining binary wrappers, they break out-of-tree builds.
[wine/multimedia.git] / loader / kthread.c
blobfcdd34db67f3d1473f27678b79bf6de8c856a064
1 /*
2 * pthread emulation based on kernel threads
4 * We can't use pthreads directly, so why not let libcs
5 * that want pthreads use Wine's own threading instead...
7 * Copyright 1999 Ove Kåven
8 * Copyright 2003 Alexandre Julliard
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "config.h"
26 #include "wine/port.h"
28 struct _pthread_cleanup_buffer;
30 #include <assert.h>
31 #include <errno.h>
32 #include <stdlib.h>
33 #include <signal.h>
34 #include <setjmp.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <string.h>
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 # include <sys/socket.h>
42 #endif
43 #ifdef HAVE_SYS_MMAN_H
44 #include <sys/mman.h>
45 #endif
46 #ifdef HAVE_NETINET_IN_H
47 # include <netinet/in.h>
48 #endif
49 #ifdef HAVE_ARPA_NAMESER_H
50 # include <arpa/nameser.h>
51 #endif
52 #ifdef HAVE_RESOLV_H
53 # include <resolv.h>
54 #endif
55 #ifdef HAVE_VALGRIND_VALGRIND_H
56 #include <valgrind/valgrind.h>
57 #endif
58 #ifdef HAVE_SYS_SYSCALL_H
59 # include <sys/syscall.h>
60 #endif
61 #ifdef HAVE_SCHED_H
62 #include <sched.h>
63 #endif
65 #include "wine/library.h"
66 #include "wine/pthread.h"
68 #define P_OUTPUT(stuff) write(2,stuff,strlen(stuff))
70 #define PSTR(str) __ASM_NAME(#str)
72 static struct wine_pthread_callbacks funcs;
74 /* thread descriptor */
76 #define FIRST_KEY 0
77 #define MAX_KEYS 16 /* libc6 doesn't use that many, but... */
78 #define MAX_TSD 16
80 struct pthread_descr_struct
82 char dummy[2048];
83 int thread_errno;
84 int thread_h_errno;
85 int cancel_state;
86 int cancel_type;
87 struct __res_state res_state;
88 const void *key_data[MAX_KEYS]; /* for normal pthread keys */
89 const void *tsd_data[MAX_TSD]; /* for libc internal tsd variables */
92 typedef struct pthread_descr_struct *pthread_descr;
94 static struct pthread_descr_struct initial_descr;
96 pthread_descr __pthread_thread_self(void)
98 struct pthread_descr_struct *descr;
99 if (!funcs.ptr_get_thread_data) return &initial_descr;
100 descr = funcs.ptr_get_thread_data();
101 if (!descr) return &initial_descr;
102 return descr;
105 static int (*libc_uselocale)(int set);
106 static int *libc_multiple_threads;
108 /***********************************************************************
109 * __errno_location/__error/__errno/___errno/__thr_errno
111 * Get the per-thread errno location.
113 int *__errno_location(void) /* Linux */
115 pthread_descr descr = __pthread_thread_self();
116 return &descr->thread_errno;
118 int *__error(void) { return __errno_location(); } /* FreeBSD */
119 int *__errno(void) { return __errno_location(); } /* NetBSD */
120 int *___errno(void) { return __errno_location(); } /* Solaris */
121 int *__thr_errno(void) { return __errno_location(); } /* UnixWare */
123 /***********************************************************************
124 * __h_errno_location
126 * Get the per-thread h_errno location.
128 int *__h_errno_location(void)
130 pthread_descr descr = __pthread_thread_self();
131 return &descr->thread_h_errno;
134 struct __res_state *__res_state(void)
136 pthread_descr descr = __pthread_thread_self();
137 return &descr->res_state;
140 static inline void writejump( const char *symbol, void *dest )
142 #if defined(__GLIBC__) && defined(__i386__)
143 unsigned char *addr = wine_dlsym( RTLD_NEXT, symbol, NULL, 0 );
145 if (!addr) return;
147 /* write a relative jump at the function address */
148 mprotect((void*)((unsigned int)addr & ~(getpagesize()-1)), 5, PROT_READ|PROT_EXEC|PROT_WRITE);
149 addr[0] = 0xe9;
150 *(int *)(addr+1) = (unsigned char *)dest - (addr + 5);
151 mprotect((void*)((unsigned int)addr & ~(getpagesize()-1)), 5, PROT_READ|PROT_EXEC);
153 # ifdef VALGRIND_DISCARD_TRANSLATIONS
154 VALGRIND_DISCARD_TRANSLATIONS( addr, 5 );
155 # endif
156 #endif /* __GLIBC__ && __i386__ */
159 /* temporary stacks used on thread exit */
160 #define TEMP_STACK_SIZE 1024
161 #define NB_TEMP_STACKS 8
162 static char temp_stacks[NB_TEMP_STACKS][TEMP_STACK_SIZE];
163 static int next_temp_stack; /* next temp stack to use */
165 /***********************************************************************
166 * get_temp_stack
168 * Get a temporary stack address to run the thread exit code on.
170 static inline char *get_temp_stack(void)
172 unsigned int next = interlocked_xchg_add( &next_temp_stack, 1 );
173 return temp_stacks[next % NB_TEMP_STACKS] + TEMP_STACK_SIZE;
177 /***********************************************************************
178 * cleanup_thread
180 * Cleanup the remains of a thread. Runs on a temporary stack.
182 static void cleanup_thread( void *ptr )
184 /* copy the info structure since it is on the stack we will free */
185 struct wine_pthread_thread_info info = *(struct wine_pthread_thread_info *)ptr;
186 wine_ldt_free_fs( info.teb_sel );
187 if (info.stack_size) munmap( info.stack_base, info.stack_size );
188 if (info.teb_size) munmap( info.teb_base, info.teb_size );
189 _exit( info.exit_status );
193 /***********************************************************************
194 * init_process
196 * Initialization for a newly created process.
198 static void init_process( const struct wine_pthread_callbacks *callbacks, size_t size )
200 memcpy( &funcs, callbacks, min( size, sizeof(funcs) ));
201 funcs.ptr_set_thread_data( &initial_descr );
205 /***********************************************************************
206 * init_thread
208 * Initialization for a newly created thread.
210 static void init_thread( struct wine_pthread_thread_info *info )
212 struct pthread_descr_struct *descr;
214 if (funcs.ptr_set_thread_data)
216 descr = calloc( 1, sizeof(*descr) );
217 funcs.ptr_set_thread_data( descr );
218 if (libc_multiple_threads) *libc_multiple_threads = 1;
220 else /* first thread */
222 descr = &initial_descr;
223 writejump( "__errno_location", __errno_location );
224 writejump( "__h_errno_location", __h_errno_location );
225 writejump( "__res_state", __res_state );
227 descr->cancel_state = PTHREAD_CANCEL_ENABLE;
228 descr->cancel_type = PTHREAD_CANCEL_ASYNCHRONOUS;
229 if (libc_uselocale) libc_uselocale( -1 /*LC_GLOBAL_LOCALE*/ );
233 /***********************************************************************
234 * create_thread
236 static int create_thread( struct wine_pthread_thread_info *info )
238 if (!info->stack_base)
240 info->stack_base = wine_anon_mmap( NULL, info->stack_size, PROT_READ | PROT_WRITE, 0 );
241 if (info->stack_base == (void *)-1) return -1;
243 #ifdef HAVE_CLONE
244 if (clone( (int (*)(void *))info->entry, (char *)info->stack_base + info->stack_size,
245 CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, info ) < 0)
246 return -1;
247 return 0;
248 #elif defined(HAVE_RFORK)
250 void **sp = (void **)((char *)info->stack_base + info->stack_size);
251 *--sp = info;
252 *--sp = 0;
253 *--sp = info->entry;
254 __asm__ __volatile__(
255 "pushl %2;\n\t" /* flags */
256 "pushl $0;\n\t" /* 0 ? */
257 "movl %1,%%eax;\n\t" /* SYS_rfork */
258 ".byte 0x9a; .long 0; .word 7;\n\t" /* lcall 7:0... FreeBSD syscall */
259 "cmpl $0, %%edx;\n\t"
260 "je 1f;\n\t"
261 "movl %0,%%esp;\n\t" /* child -> new thread */
262 "ret;\n"
263 "1:\n\t" /* parent -> caller thread */
264 "addl $8,%%esp" :
265 : "r" (sp), "r" (SYS_rfork), "r" (RFPROC | RFMEM | RFTHREAD)
266 : "eax", "edx");
267 return 0;
269 #endif
270 return -1;
274 /***********************************************************************
275 * init_current_teb
277 * Set the current TEB for a new thread.
279 static void init_current_teb( struct wine_pthread_thread_info *info )
281 /* On the i386, the current thread is in the %fs register */
282 LDT_ENTRY fs_entry;
284 wine_ldt_set_base( &fs_entry, info->teb_base );
285 wine_ldt_set_limit( &fs_entry, info->teb_size - 1 );
286 wine_ldt_set_flags( &fs_entry, WINE_LDT_FLAGS_DATA|WINE_LDT_FLAGS_32BIT );
287 wine_ldt_init_fs( info->teb_sel, &fs_entry );
289 /* set pid and tid */
290 info->pid = getpid();
291 info->tid = -1;
295 /***********************************************************************
296 * get_current_teb
298 static void *get_current_teb(void)
300 void *ret;
301 __asm__( ".byte 0x64\n\tmovl 0x18,%0" : "=r" (ret) );
302 return ret;
306 /***********************************************************************
307 * exit_thread
309 static void DECLSPEC_NORETURN exit_thread( struct wine_pthread_thread_info *info )
311 wine_switch_to_stack( cleanup_thread, info, get_temp_stack() );
315 /***********************************************************************
316 * abort_thread
318 static void DECLSPEC_NORETURN abort_thread( long status )
320 _exit( status );
324 /***********************************************************************
325 * pthread_functions
327 static const struct wine_pthread_functions pthread_functions =
329 init_process,
330 init_thread,
331 create_thread,
332 init_current_teb,
333 get_current_teb,
334 exit_thread,
335 abort_thread,
336 sigprocmask
339 void init_pthread_functions(void)
341 wine_pthread_set_functions( &pthread_functions, sizeof(pthread_functions) );
344 /* Currently this probably works only for glibc2,
345 * which checks for the presence of double-underscore-prepended
346 * pthread primitives, and use them if available.
347 * If they are not available, the libc defaults to
348 * non-threadsafe operation (not good). */
350 #if defined(HAVE_PTHREAD_H) && (defined(__GLIBC__) || defined(__FreeBSD__))
352 /* adapt as necessary (a construct like this is used in glibc sources) */
353 #define strong_alias(orig, alias) \
354 asm(".globl " PSTR(alias) "\n" \
355 "\t.set " PSTR(alias) "," PSTR(orig))
357 struct fork_block;
359 /* pthread functions redirection */
361 struct pthread_functions
363 pid_t (*ptr_pthread_fork) (struct fork_block *);
364 int (*ptr_pthread_attr_destroy) (pthread_attr_t *);
365 int (*ptr___pthread_attr_init_2_0) (pthread_attr_t *);
366 int (*ptr___pthread_attr_init_2_1) (pthread_attr_t *);
367 int (*ptr_pthread_attr_getdetachstate) (const pthread_attr_t *, int *);
368 int (*ptr_pthread_attr_setdetachstate) (pthread_attr_t *, int);
369 int (*ptr_pthread_attr_getinheritsched) (const pthread_attr_t *, int *);
370 int (*ptr_pthread_attr_setinheritsched) (pthread_attr_t *, int);
371 int (*ptr_pthread_attr_getschedparam) (const pthread_attr_t *, struct sched_param *);
372 int (*ptr_pthread_attr_setschedparam) (pthread_attr_t *, const struct sched_param *);
373 int (*ptr_pthread_attr_getschedpolicy) (const pthread_attr_t *, int *);
374 int (*ptr_pthread_attr_setschedpolicy) (pthread_attr_t *, int);
375 int (*ptr_pthread_attr_getscope) (const pthread_attr_t *, int *);
376 int (*ptr_pthread_attr_setscope) (pthread_attr_t *, int);
377 int (*ptr_pthread_condattr_destroy) (pthread_condattr_t *);
378 int (*ptr_pthread_condattr_init) (pthread_condattr_t *);
379 int (*ptr___pthread_cond_broadcast) (pthread_cond_t *);
380 int (*ptr___pthread_cond_destroy) (pthread_cond_t *);
381 int (*ptr___pthread_cond_init) (pthread_cond_t *, const pthread_condattr_t *);
382 int (*ptr___pthread_cond_signal) (pthread_cond_t *);
383 int (*ptr___pthread_cond_wait) (pthread_cond_t *, pthread_mutex_t *);
384 int (*ptr_pthread_equal) (pthread_t, pthread_t);
385 void (*ptr___pthread_exit) (void *);
386 int (*ptr_pthread_getschedparam) (pthread_t, int *, struct sched_param *);
387 int (*ptr_pthread_setschedparam) (pthread_t, int, const struct sched_param *);
388 int (*ptr_pthread_mutex_destroy) (pthread_mutex_t *);
389 int (*ptr_pthread_mutex_init) (pthread_mutex_t *, const pthread_mutexattr_t *);
390 int (*ptr_pthread_mutex_lock) (pthread_mutex_t *);
391 int (*ptr_pthread_mutex_trylock) (pthread_mutex_t *);
392 int (*ptr_pthread_mutex_unlock) (pthread_mutex_t *);
393 pthread_t (*ptr_pthread_self) (void);
394 int (*ptr_pthread_setcancelstate) (int, int *);
395 int (*ptr_pthread_setcanceltype) (int, int *);
396 void (*ptr_pthread_do_exit) (void *retval, char *currentframe);
397 void (*ptr_pthread_cleanup_upto) (jmp_buf target, char *targetframe);
398 pthread_descr (*ptr_pthread_thread_self) (void);
399 int (*ptr_pthread_internal_tsd_set) (int key, const void *pointer);
400 void * (*ptr_pthread_internal_tsd_get) (int key);
401 void ** __attribute__ ((__const__)) (*ptr_pthread_internal_tsd_address) (int key);
402 int (*ptr_pthread_sigaction) (int sig, const struct sigaction * act, struct sigaction *oact);
403 int (*ptr_pthread_sigwait) (const sigset_t *set, int *sig);
404 int (*ptr_pthread_raise) (int sig);
405 int (*ptr___pthread_cond_timedwait) (pthread_cond_t *, pthread_mutex_t *, const struct timespec *);
406 void (*ptr__pthread_cleanup_push) (struct _pthread_cleanup_buffer * buffer, void (*routine)(void *), void * arg);
407 void (*ptr__pthread_cleanup_pop) (struct _pthread_cleanup_buffer * buffer, int execute);
410 static pid_t (*libc_fork)(void);
411 static int (*libc_sigaction)(int signum, const struct sigaction *act, struct sigaction *oldact);
412 static int *(*libc_pthread_init)( const struct pthread_functions *funcs );
414 static struct pthread_functions libc_pthread_functions;
416 strong_alias(__pthread_thread_self, pthread_thread_self);
418 /* redefine this to prevent libpthread from overriding our function pointers */
419 int *__libc_pthread_init( const struct pthread_functions *funcs )
421 return libc_multiple_threads;
424 typedef struct _wine_cleanup {
425 void (*routine)(void *);
426 void *arg;
427 } *wine_cleanup;
429 int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void*
430 (*start_routine)(void *), void* arg)
432 assert( funcs.ptr_pthread_create );
433 return funcs.ptr_pthread_create( thread, attr, start_routine, arg );
436 int pthread_cancel(pthread_t thread)
438 assert( funcs.ptr_pthread_cancel );
439 return funcs.ptr_pthread_cancel( thread );
442 int pthread_join(pthread_t thread, void **value_ptr)
444 assert( funcs.ptr_pthread_join );
445 return funcs.ptr_pthread_join( thread, value_ptr );
448 int pthread_detach(pthread_t thread)
450 assert( funcs.ptr_pthread_detach );
451 return funcs.ptr_pthread_detach( thread );
454 /* FIXME: we have no equivalents in win32 for the policys */
455 /* so just keep this as a stub */
456 int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
458 P_OUTPUT("FIXME:pthread_attr_setschedpolicy\n");
459 return 0;
462 /* FIXME: no win32 equivalent for scope */
463 int pthread_attr_setscope(pthread_attr_t *attr, int scope)
465 P_OUTPUT("FIXME:pthread_attr_setscope\n");
466 return 0; /* return success */
469 /* FIXME: no win32 equivalent for schedule param */
470 int pthread_attr_setschedparam(pthread_attr_t *attr,
471 const struct sched_param *param)
473 P_OUTPUT("FIXME:pthread_attr_setschedparam\n");
474 return 0; /* return success */
477 /* FIXME */
478 int pthread_attr_setstack(pthread_attr_t *attr, void *addr, size_t size)
480 return 0; /* return success */
483 int __pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
485 static pthread_once_t the_once = PTHREAD_ONCE_INIT;
486 int once_now;
488 memcpy(&once_now,&the_once,sizeof(once_now));
489 if (interlocked_cmpxchg((int*)once_control, once_now+1, once_now) == once_now)
490 (*init_routine)();
491 return 0;
493 strong_alias(__pthread_once, pthread_once);
495 void __pthread_kill_other_threads_np(void)
497 /* we don't need to do anything here */
499 strong_alias(__pthread_kill_other_threads_np, pthread_kill_other_threads_np);
501 /***** atfork *****/
503 #define MAX_ATFORK 8 /* libc doesn't need that many anyway */
505 static pthread_mutex_t atfork_mutex = PTHREAD_MUTEX_INITIALIZER;
507 typedef void (*atfork_handler)(void);
508 static atfork_handler atfork_prepare[MAX_ATFORK];
509 static atfork_handler atfork_parent[MAX_ATFORK];
510 static atfork_handler atfork_child[MAX_ATFORK];
511 static int atfork_count;
513 int __pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
515 pthread_mutex_lock( &atfork_mutex );
516 assert( atfork_count < MAX_ATFORK );
517 atfork_prepare[atfork_count] = prepare;
518 atfork_parent[atfork_count] = parent;
519 atfork_child[atfork_count] = child;
520 atfork_count++;
521 pthread_mutex_unlock( &atfork_mutex );
522 return 0;
524 strong_alias(__pthread_atfork, pthread_atfork);
526 pid_t __fork(void)
528 pid_t pid;
529 int i;
531 if (!libc_fork)
533 libc_fork = wine_dlsym( RTLD_NEXT, "fork", NULL, 0 );
534 assert( libc_fork );
536 pthread_mutex_lock( &atfork_mutex );
537 /* prepare handlers are called in reverse insertion order */
538 for (i = atfork_count - 1; i >= 0; i--) if (atfork_prepare[i]) atfork_prepare[i]();
539 if (!(pid = libc_fork()))
541 pthread_mutex_init( &atfork_mutex, NULL );
542 for (i = 0; i < atfork_count; i++) if (atfork_child[i]) atfork_child[i]();
544 else
546 for (i = 0; i < atfork_count; i++) if (atfork_parent[i]) atfork_parent[i]();
547 pthread_mutex_unlock( &atfork_mutex );
549 return pid;
551 strong_alias(__fork, fork);
553 /***** MUTEXES *****/
555 int __pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
557 if (!funcs.ptr_pthread_mutex_init) return 0;
558 return funcs.ptr_pthread_mutex_init( mutex, mutexattr );
560 strong_alias(__pthread_mutex_init, pthread_mutex_init);
562 int __pthread_mutex_lock(pthread_mutex_t *mutex)
564 if (!funcs.ptr_pthread_mutex_lock) return 0;
565 return funcs.ptr_pthread_mutex_lock( mutex );
567 strong_alias(__pthread_mutex_lock, pthread_mutex_lock);
569 int __pthread_mutex_trylock(pthread_mutex_t *mutex)
571 if (!funcs.ptr_pthread_mutex_trylock) return 0;
572 return funcs.ptr_pthread_mutex_trylock( mutex );
574 strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock);
576 int __pthread_mutex_unlock(pthread_mutex_t *mutex)
578 if (!funcs.ptr_pthread_mutex_unlock) return 0;
579 return funcs.ptr_pthread_mutex_unlock( mutex );
581 strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock);
583 int __pthread_mutex_destroy(pthread_mutex_t *mutex)
585 if (!funcs.ptr_pthread_mutex_destroy) return 0;
586 return funcs.ptr_pthread_mutex_destroy( mutex );
588 strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy);
591 /***** MUTEX ATTRIBUTES *****/
592 /* just dummies, since critical sections are always recursive */
594 int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
596 return 0;
598 strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init);
600 int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
602 return 0;
604 strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy);
606 int __pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind)
608 return 0;
610 strong_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np);
612 int __pthread_mutexattr_getkind_np(pthread_mutexattr_t *attr, int *kind)
614 *kind = PTHREAD_MUTEX_RECURSIVE;
615 return 0;
617 strong_alias(__pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np);
619 int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind)
621 return 0;
623 strong_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype);
625 int __pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *kind)
627 *kind = PTHREAD_MUTEX_RECURSIVE;
628 return 0;
630 strong_alias(__pthread_mutexattr_gettype, pthread_mutexattr_gettype);
633 /***** THREAD-SPECIFIC VARIABLES (KEYS) *****/
635 int __pthread_key_create(pthread_key_t *key, void (*destr_function)(void *))
637 static int keycnt = FIRST_KEY;
638 *key = interlocked_xchg_add(&keycnt, 1);
639 return 0;
641 strong_alias(__pthread_key_create, pthread_key_create);
643 int __pthread_key_delete(pthread_key_t key)
645 return 0;
647 strong_alias(__pthread_key_delete, pthread_key_delete);
649 int __pthread_setspecific(pthread_key_t key, const void *pointer)
651 pthread_descr descr = __pthread_thread_self();
652 descr->key_data[key] = pointer;
653 return 0;
655 strong_alias(__pthread_setspecific, pthread_setspecific);
657 void *__pthread_getspecific(pthread_key_t key)
659 pthread_descr descr = __pthread_thread_self();
660 return (void *)descr->key_data[key];
662 strong_alias(__pthread_getspecific, pthread_getspecific);
664 static int pthread_internal_tsd_set( int key, const void *pointer )
666 pthread_descr descr = __pthread_thread_self();
667 descr->tsd_data[key] = pointer;
668 return 0;
670 int (*__libc_internal_tsd_set)(int, const void *) = pthread_internal_tsd_set;
672 static void *pthread_internal_tsd_get( int key )
674 pthread_descr descr = __pthread_thread_self();
675 return (void *)descr->tsd_data[key];
677 void* (*__libc_internal_tsd_get)(int) = pthread_internal_tsd_get;
679 static void ** __attribute__((const)) pthread_internal_tsd_address( int key )
681 pthread_descr descr = __pthread_thread_self();
682 return (void **)&descr->tsd_data[key];
684 void** (*__libc_internal_tsd_address)(int) = pthread_internal_tsd_address;
686 /***** "EXCEPTION" FRAMES *****/
687 /* not implemented right now */
689 void _pthread_cleanup_push(struct _pthread_cleanup_buffer *buffer, void (*routine)(void *), void *arg)
691 ((wine_cleanup)buffer)->routine = routine;
692 ((wine_cleanup)buffer)->arg = arg;
695 void _pthread_cleanup_pop(struct _pthread_cleanup_buffer *buffer, int execute)
697 if (execute) (*(((wine_cleanup)buffer)->routine))(((wine_cleanup)buffer)->arg);
700 void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer *buffer, void (*routine)(void *), void *arg)
702 _pthread_cleanup_push(buffer, routine, arg);
705 void _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer *buffer, int execute)
707 _pthread_cleanup_pop(buffer, execute);
710 void __pthread_cleanup_upto(jmp_buf target, char *frame)
712 /* FIXME */
715 /***** CONDITIONS *****/
717 int __pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
719 if (!funcs.ptr_pthread_cond_init) return 0;
720 return funcs.ptr_pthread_cond_init(cond, cond_attr);
722 strong_alias(__pthread_cond_init, pthread_cond_init);
724 int __pthread_cond_destroy(pthread_cond_t *cond)
726 if (!funcs.ptr_pthread_cond_destroy) return 0;
727 return funcs.ptr_pthread_cond_destroy(cond);
729 strong_alias(__pthread_cond_destroy, pthread_cond_destroy);
731 int __pthread_cond_signal(pthread_cond_t *cond)
733 if (!funcs.ptr_pthread_cond_signal) return 0;
734 return funcs.ptr_pthread_cond_signal(cond);
736 strong_alias(__pthread_cond_signal, pthread_cond_signal);
738 int __pthread_cond_broadcast(pthread_cond_t *cond)
740 if (!funcs.ptr_pthread_cond_broadcast) return 0;
741 return funcs.ptr_pthread_cond_broadcast(cond);
743 strong_alias(__pthread_cond_broadcast, pthread_cond_broadcast);
745 int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
747 if (!funcs.ptr_pthread_cond_wait) return 0;
748 return funcs.ptr_pthread_cond_wait(cond, mutex);
750 strong_alias(__pthread_cond_wait, pthread_cond_wait);
752 int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
754 if (!funcs.ptr_pthread_cond_timedwait) return 0;
755 return funcs.ptr_pthread_cond_timedwait(cond, mutex, abstime);
757 strong_alias(__pthread_cond_timedwait, pthread_cond_timedwait);
759 /**** CONDITION ATTRIBUTES *****/
760 /* not implemented right now */
762 int pthread_condattr_init(pthread_condattr_t *attr)
764 return 0;
767 int pthread_condattr_destroy(pthread_condattr_t *attr)
769 return 0;
772 /***** READ-WRITE LOCKS *****/
774 int __pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *rwlock_attr)
776 assert( funcs.ptr_pthread_rwlock_init );
777 return funcs.ptr_pthread_rwlock_init( rwlock, rwlock_attr );
779 strong_alias(__pthread_rwlock_init, pthread_rwlock_init);
781 int __pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
783 assert( funcs.ptr_pthread_rwlock_destroy );
784 return funcs.ptr_pthread_rwlock_destroy( rwlock );
786 strong_alias(__pthread_rwlock_destroy, pthread_rwlock_destroy);
788 int __pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
790 if (!funcs.ptr_pthread_rwlock_rdlock) return 0;
791 return funcs.ptr_pthread_rwlock_rdlock( rwlock );
793 strong_alias(__pthread_rwlock_rdlock, pthread_rwlock_rdlock);
795 int __pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
797 assert( funcs.ptr_pthread_rwlock_tryrdlock );
798 return funcs.ptr_pthread_rwlock_tryrdlock( rwlock );
800 strong_alias(__pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock);
802 int __pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
804 assert( funcs.ptr_pthread_rwlock_wrlock );
805 return funcs.ptr_pthread_rwlock_wrlock( rwlock );
807 strong_alias(__pthread_rwlock_wrlock, pthread_rwlock_wrlock);
809 int __pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
811 assert( funcs.ptr_pthread_rwlock_trywrlock );
812 return funcs.ptr_pthread_rwlock_trywrlock( rwlock );
814 strong_alias(__pthread_rwlock_trywrlock, pthread_rwlock_trywrlock);
816 int __pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
818 if (!funcs.ptr_pthread_rwlock_unlock) return 0;
819 return funcs.ptr_pthread_rwlock_unlock( rwlock );
821 strong_alias(__pthread_rwlock_unlock, pthread_rwlock_unlock);
823 /**** READ-WRITE LOCK ATTRIBUTES *****/
824 /* not implemented right now */
826 int pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
828 return 0;
831 int __pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
833 return 0;
835 strong_alias(__pthread_rwlockattr_destroy, pthread_rwlockattr_destroy);
837 int pthread_rwlockattr_getkind_np(const pthread_rwlockattr_t *attr, int *pref)
839 *pref = 0;
840 return 0;
843 int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *attr, int pref)
845 return 0;
848 /***** MISC *****/
850 pthread_t pthread_self(void)
852 assert( funcs.ptr_pthread_self );
853 return funcs.ptr_pthread_self();
856 int pthread_equal(pthread_t thread1, pthread_t thread2)
858 assert( funcs.ptr_pthread_equal );
859 return funcs.ptr_pthread_equal( thread1, thread2 );
862 void __pthread_do_exit(void *retval, char *currentframe)
864 assert( funcs.ptr_pthread_exit );
865 return funcs.ptr_pthread_exit( retval, currentframe );
868 void __pthread_exit(void *retval)
870 __pthread_do_exit( retval, NULL );
872 strong_alias(__pthread_exit, pthread_exit);
874 int pthread_setcancelstate(int state, int *oldstate)
876 pthread_descr descr = __pthread_thread_self();
877 if (oldstate) *oldstate = descr->cancel_state;
878 descr->cancel_state = state;
879 return 0;
882 int pthread_setcanceltype(int type, int *oldtype)
884 pthread_descr descr = __pthread_thread_self();
885 if (oldtype) *oldtype = descr->cancel_type;
886 descr->cancel_type = type;
887 return 0;
890 /***** ANTI-OVERRIDES *****/
891 /* pthreads tries to override these, point them back to libc */
893 int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
895 if (!libc_sigaction)
897 libc_sigaction = wine_dlsym( RTLD_NEXT, "sigaction", NULL, 0 );
898 assert( libc_sigaction );
900 return libc_sigaction(signum, act, oldact);
903 void __pthread_initialize(void)
905 static int done;
907 if (!done)
909 done = 1;
910 libc_fork = wine_dlsym( RTLD_NEXT, "fork", NULL, 0 );
911 libc_sigaction = wine_dlsym( RTLD_NEXT, "sigaction", NULL, 0 );
912 libc_uselocale = wine_dlsym( RTLD_DEFAULT, "uselocale", NULL, 0 );
913 libc_pthread_init = wine_dlsym( RTLD_NEXT, "__libc_pthread_init", NULL, 0 );
914 if (libc_pthread_init) libc_multiple_threads = libc_pthread_init( &libc_pthread_functions );
918 #ifdef __GNUC__
919 static void init(void) __attribute__((constructor));
920 static void init(void)
922 __pthread_initialize();
924 #endif
926 static struct pthread_functions libc_pthread_functions =
928 NULL, /* ptr_pthread_fork */
929 NULL, /* FIXME */ /* ptr_pthread_attr_destroy */
930 NULL, /* FIXME */ /* ptr___pthread_attr_init_2_0 */
931 NULL, /* FIXME */ /* ptr___pthread_attr_init_2_1 */
932 NULL, /* FIXME */ /* ptr_pthread_attr_getdetachstate */
933 NULL, /* FIXME */ /* ptr_pthread_attr_setdetachstate */
934 NULL, /* FIXME */ /* ptr_pthread_attr_getinheritsched */
935 NULL, /* FIXME */ /* ptr_pthread_attr_setinheritsched */
936 NULL, /* FIXME */ /* ptr_pthread_attr_getschedparam */
937 pthread_attr_setschedparam, /* ptr_pthread_attr_setschedparam */
938 NULL, /* FIXME */ /* ptr_pthread_attr_getschedpolicy */
939 NULL, /* FIXME */ /* ptr_pthread_attr_setschedpolicy */
940 NULL, /* FIXME */ /* ptr_pthread_attr_getscope */
941 NULL, /* FIXME */ /* ptr_pthread_attr_setscope */
942 pthread_condattr_destroy, /* ptr_pthread_condattr_destroy */
943 pthread_condattr_init, /* ptr_pthread_condattr_init */
944 __pthread_cond_broadcast, /* ptr___pthread_cond_broadcast */
945 __pthread_cond_destroy, /* ptr___pthread_cond_destroy */
946 __pthread_cond_init, /* ptr___pthread_cond_init */
947 __pthread_cond_signal, /* ptr___pthread_cond_signal */
948 __pthread_cond_wait, /* ptr___pthread_cond_wait */
949 pthread_equal, /* ptr_pthread_equal */
950 __pthread_exit, /* ptr___pthread_exit */
951 NULL, /* FIXME */ /* ptr_pthread_getschedparam */
952 NULL, /* FIXME */ /* ptr_pthread_setschedparam */
953 __pthread_mutex_destroy, /* ptr_pthread_mutex_destroy */
954 __pthread_mutex_init, /* ptr_pthread_mutex_init */
955 __pthread_mutex_lock, /* ptr_pthread_mutex_lock */
956 __pthread_mutex_trylock, /* ptr_pthread_mutex_trylock */
957 __pthread_mutex_unlock, /* ptr_pthread_mutex_unlock */
958 pthread_self, /* ptr_pthread_self */
959 pthread_setcancelstate, /* ptr_pthread_setcancelstate */
960 pthread_setcanceltype, /* ptr_pthread_setcanceltype */
961 __pthread_do_exit, /* ptr_pthread_do_exit */
962 __pthread_cleanup_upto, /* ptr_pthread_cleanup_upto */
963 __pthread_thread_self, /* ptr_pthread_thread_self */
964 pthread_internal_tsd_set, /* ptr_pthread_internal_tsd_set */
965 pthread_internal_tsd_get, /* ptr_pthread_internal_tsd_get */
966 pthread_internal_tsd_address, /* ptr_pthread_internal_tsd_address */
967 NULL, /* ptr_pthread_sigaction */
968 NULL, /* ptr_pthread_sigwait */
969 NULL, /* ptr_pthread_raise */
970 __pthread_cond_timedwait, /* ptr___pthread_cond_timedwait */
971 _pthread_cleanup_push, /* ptr__pthread_cleanup_push */
972 _pthread_cleanup_pop /* ptr__pthread_cleanup_pop */
975 #endif /* HAVE_PTHREAD_H && (__GLIBC__ || __FREEBSD__) */