blob: 2b64e27b4364b735524e7be0bce2c387dfe05b81 [file] [log] [blame]
Ove Kaavenf19f07d2000-04-14 14:47:02 +00001/*
Alexandre Julliardf45325e2003-11-06 23:05:41 +00002 * pthread emulation based on kernel threads
Ove Kaavenf19f07d2000-04-14 14:47:02 +00003 *
4 * We can't use pthreads directly, so why not let libcs
Andreas Mohr9cef2d02001-11-19 02:30:01 +00005 * that want pthreads use Wine's own threading instead...
Ove Kaavenf19f07d2000-04-14 14:47:02 +00006 *
7 * Copyright 1999 Ove Kåven
Alexandre Julliard80e34db2003-09-03 00:26:08 +00008 * Copyright 2003 Alexandre Julliard
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00009 *
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.
14 *
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.
19 *
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
Jonathan Ernst360a3f92006-05-18 14:49:52 +020022 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Ove Kaavenf19f07d2000-04-14 14:47:02 +000023 */
24
25#include "config.h"
Alexandre Julliard5769d1d2002-04-26 19:05:15 +000026#include "wine/port.h"
27
Alexandre Julliard03d79982003-08-15 03:55:06 +000028struct _pthread_cleanup_buffer;
29
Alexandre Julliard95a43322000-05-01 16:19:40 +000030#include <assert.h>
Ove Kaavenf19f07d2000-04-14 14:47:02 +000031#include <errno.h>
32#include <stdlib.h>
Alexandre Julliard80e34db2003-09-03 00:26:08 +000033#include <signal.h>
Alexandre Julliard97d862c2003-08-12 18:59:13 +000034#include <setjmp.h>
Patrik Stridvalld016f812002-08-17 00:43:16 +000035#ifdef HAVE_UNISTD_H
36# include <unistd.h>
37#endif
Jeff Garzikf46eb1d2001-03-21 20:30:46 +000038#include <string.h>
Alexandre Julliard03d79982003-08-15 03:55:06 +000039#include <sys/types.h>
Daniel Marmiera613de22003-09-30 00:33:47 +000040#ifdef HAVE_SYS_SOCKET_H
Alexandre Julliard03d79982003-08-15 03:55:06 +000041# 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
Pierre d'Herbemontae8ca362003-10-27 21:55:00 +000049#ifdef HAVE_ARPA_NAMESER_H
50# include <arpa/nameser.h>
51#endif
Alexandre Julliard03d79982003-08-15 03:55:06 +000052#ifdef HAVE_RESOLV_H
53# include <resolv.h>
54#endif
55#ifdef HAVE_VALGRIND_MEMCHECK_H
56#include <valgrind/memcheck.h>
57#endif
Alexandre Julliardf45325e2003-11-06 23:05:41 +000058#ifdef HAVE_SYS_SYSCALL_H
59# include <sys/syscall.h>
60#endif
Alexandre Julliardf45325e2003-11-06 23:05:41 +000061#ifdef HAVE_SCHED_H
62#include <sched.h>
63#endif
Ove Kaavenf19f07d2000-04-14 14:47:02 +000064
Alexandre Julliard85744122003-11-05 23:31:11 +000065#include "wine/library.h"
Alexandre Julliard80e34db2003-09-03 00:26:08 +000066#include "wine/pthread.h"
Ove Kaavenf19f07d2000-04-14 14:47:02 +000067
Alexandre Julliard80e34db2003-09-03 00:26:08 +000068#define P_OUTPUT(stuff) write(2,stuff,strlen(stuff))
69
70#define PSTR(str) __ASM_NAME(#str)
71
Alexandre Julliard883d3c52005-09-03 15:11:29 +000072static struct wine_pthread_callbacks funcs;
Alexandre Julliard80e34db2003-09-03 00:26:08 +000073
74/* thread descriptor */
75
76#define FIRST_KEY 0
77#define MAX_KEYS 16 /* libc6 doesn't use that many, but... */
78#define MAX_TSD 16
79
80struct pthread_descr_struct
Alexandre Julliard03d79982003-08-15 03:55:06 +000081{
Alexandre Julliard80e34db2003-09-03 00:26:08 +000082 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 */
90};
91
92typedef struct pthread_descr_struct *pthread_descr;
93
94static struct pthread_descr_struct initial_descr;
95
96pthread_descr __pthread_thread_self(void)
97{
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;
Alexandre Julliard03d79982003-08-15 03:55:06 +0000103}
104
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000105static int (*libc_uselocale)(int set);
106static int *libc_multiple_threads;
Alexandre Julliard03d79982003-08-15 03:55:06 +0000107
108/***********************************************************************
109 * __errno_location/__error/__errno/___errno/__thr_errno
110 *
111 * Get the per-thread errno location.
112 */
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000113int *__errno_location(void) /* Linux */
114{
115 pthread_descr descr = __pthread_thread_self();
116 return &descr->thread_errno;
117}
118int *__error(void) { return __errno_location(); } /* FreeBSD */
119int *__errno(void) { return __errno_location(); } /* NetBSD */
120int *___errno(void) { return __errno_location(); } /* Solaris */
121int *__thr_errno(void) { return __errno_location(); } /* UnixWare */
Alexandre Julliard03d79982003-08-15 03:55:06 +0000122
123/***********************************************************************
124 * __h_errno_location
125 *
126 * Get the per-thread h_errno location.
127 */
128int *__h_errno_location(void)
129{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000130 pthread_descr descr = __pthread_thread_self();
131 return &descr->thread_h_errno;
132}
133
Gabriele Giorgetti59b2ad62003-09-18 20:52:24 +0000134struct __res_state *__res_state(void)
135{
136 pthread_descr descr = __pthread_thread_self();
137 return &descr->res_state;
138}
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000139
140static inline void writejump( const char *symbol, void *dest )
141{
142#if defined(__GLIBC__) && defined(__i386__)
Alexandre Julliard9bfe0c42004-06-24 04:07:22 +0000143 unsigned char *addr = wine_dlsym( RTLD_NEXT, symbol, NULL, 0 );
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000144
145 if (!addr) return;
146
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);
152
153# ifdef HAVE_VALGRIND_MEMCHECK_H
154 VALGRIND_DISCARD_TRANSLATIONS( addr, 5 );
155# endif
156#endif /* __GLIBC__ && __i386__ */
157}
158
Alexandre Julliard85744122003-11-05 23:31:11 +0000159/* temporary stacks used on thread exit */
160#define TEMP_STACK_SIZE 1024
161#define NB_TEMP_STACKS 8
162static char temp_stacks[NB_TEMP_STACKS][TEMP_STACK_SIZE];
Alexandre Julliard43c63962005-09-26 13:51:58 +0000163static int next_temp_stack; /* next temp stack to use */
Alexandre Julliard85744122003-11-05 23:31:11 +0000164
165/***********************************************************************
166 * get_temp_stack
167 *
168 * Get a temporary stack address to run the thread exit code on.
169 */
Andrew Talbotcb5dcc62007-03-26 20:27:22 +0100170static inline char *get_temp_stack(void)
Alexandre Julliard85744122003-11-05 23:31:11 +0000171{
172 unsigned int next = interlocked_xchg_add( &next_temp_stack, 1 );
173 return temp_stacks[next % NB_TEMP_STACKS] + TEMP_STACK_SIZE;
174}
175
176
177/***********************************************************************
178 * cleanup_thread
179 *
180 * Cleanup the remains of a thread. Runs on a temporary stack.
181 */
182static void cleanup_thread( void *ptr )
183{
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 );
Alexandre Julliardc79cf022006-07-13 20:47:07 +0200187 if (info.stack_size) munmap( info.stack_base, info.stack_size );
188 if (info.teb_size) munmap( info.teb_base, info.teb_size );
Alexandre Julliard85744122003-11-05 23:31:11 +0000189 _exit( info.exit_status );
190}
191
192
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000193/***********************************************************************
Alexandre Julliard883d3c52005-09-03 15:11:29 +0000194 * init_process
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000195 *
196 * Initialization for a newly created process.
197 */
Alexandre Julliard883d3c52005-09-03 15:11:29 +0000198static void init_process( const struct wine_pthread_callbacks *callbacks, size_t size )
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000199{
Alexandre Julliard883d3c52005-09-03 15:11:29 +0000200 memcpy( &funcs, callbacks, min( size, sizeof(funcs) ));
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000201 funcs.ptr_set_thread_data( &initial_descr );
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000202}
203
204
205/***********************************************************************
Alexandre Julliard883d3c52005-09-03 15:11:29 +0000206 * init_thread
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000207 *
208 * Initialization for a newly created thread.
209 */
Alexandre Julliard883d3c52005-09-03 15:11:29 +0000210static void init_thread( struct wine_pthread_thread_info *info )
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000211{
Alexandre Julliardcf4ca4e2003-10-12 02:26:20 +0000212 struct pthread_descr_struct *descr;
213
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000214 if (funcs.ptr_set_thread_data)
215 {
Alexandre Julliardcf4ca4e2003-10-12 02:26:20 +0000216 descr = calloc( 1, sizeof(*descr) );
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000217 funcs.ptr_set_thread_data( descr );
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000218 if (libc_multiple_threads) *libc_multiple_threads = 1;
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000219 }
Alexandre Julliardcf4ca4e2003-10-12 02:26:20 +0000220 else /* first thread */
221 {
222 descr = &initial_descr;
223 writejump( "__errno_location", __errno_location );
224 writejump( "__h_errno_location", __h_errno_location );
225 writejump( "__res_state", __res_state );
226 }
227 descr->cancel_state = PTHREAD_CANCEL_ENABLE;
228 descr->cancel_type = PTHREAD_CANCEL_ASYNCHRONOUS;
229 if (libc_uselocale) libc_uselocale( -1 /*LC_GLOBAL_LOCALE*/ );
Alexandre Julliard03d79982003-08-15 03:55:06 +0000230}
231
232
Alexandre Julliard85744122003-11-05 23:31:11 +0000233/***********************************************************************
Alexandre Julliard883d3c52005-09-03 15:11:29 +0000234 * create_thread
Alexandre Julliard85744122003-11-05 23:31:11 +0000235 */
Alexandre Julliard883d3c52005-09-03 15:11:29 +0000236static int create_thread( struct wine_pthread_thread_info *info )
Alexandre Julliard85744122003-11-05 23:31:11 +0000237{
238 if (!info->stack_base)
239 {
Alexandre Julliard338fc522006-12-05 15:42:53 +0100240 info->stack_base = wine_anon_mmap( NULL, info->stack_size, PROT_READ | PROT_WRITE, 0 );
Alexandre Julliard85744122003-11-05 23:31:11 +0000241 if (info->stack_base == (void *)-1) return -1;
242 }
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)
249 {
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" :
Peter Chapman505dfde2004-12-02 18:19:25 +0000265 : "r" (sp), "r" (SYS_rfork), "r" (RFPROC | RFMEM | RFTHREAD)
Alexandre Julliard85744122003-11-05 23:31:11 +0000266 : "eax", "edx");
267 return 0;
268 }
Alexandre Julliard85744122003-11-05 23:31:11 +0000269#endif
270 return -1;
271}
272
273
274/***********************************************************************
Alexandre Julliard883d3c52005-09-03 15:11:29 +0000275 * init_current_teb
Alexandre Julliard4fac95d2004-02-05 02:01:35 +0000276 *
277 * Set the current TEB for a new thread.
278 */
Alexandre Julliard883d3c52005-09-03 15:11:29 +0000279static void init_current_teb( struct wine_pthread_thread_info *info )
Alexandre Julliard4fac95d2004-02-05 02:01:35 +0000280{
Alexandre Julliard4fac95d2004-02-05 02:01:35 +0000281 /* On the i386, the current thread is in the %fs register */
282 LDT_ENTRY fs_entry;
283
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 );
Alexandre Julliard4fac95d2004-02-05 02:01:35 +0000288
289 /* set pid and tid */
290 info->pid = getpid();
Alexandre Julliard4fac95d2004-02-05 02:01:35 +0000291 info->tid = -1;
Alexandre Julliard4fac95d2004-02-05 02:01:35 +0000292}
293
294
295/***********************************************************************
Alexandre Julliard883d3c52005-09-03 15:11:29 +0000296 * get_current_teb
Alexandre Julliard50fba7f2003-11-09 01:25:23 +0000297 */
Alexandre Julliard883d3c52005-09-03 15:11:29 +0000298static void *get_current_teb(void)
Alexandre Julliard50fba7f2003-11-09 01:25:23 +0000299{
300 void *ret;
Alexandre Julliard50fba7f2003-11-09 01:25:23 +0000301 __asm__( ".byte 0x64\n\tmovl 0x18,%0" : "=r" (ret) );
Alexandre Julliard50fba7f2003-11-09 01:25:23 +0000302 return ret;
303}
304
305
306/***********************************************************************
Alexandre Julliard883d3c52005-09-03 15:11:29 +0000307 * exit_thread
Alexandre Julliard85744122003-11-05 23:31:11 +0000308 */
Alexandre Julliard883d3c52005-09-03 15:11:29 +0000309static void DECLSPEC_NORETURN exit_thread( struct wine_pthread_thread_info *info )
Alexandre Julliard85744122003-11-05 23:31:11 +0000310{
311 wine_switch_to_stack( cleanup_thread, info, get_temp_stack() );
312}
313
314
315/***********************************************************************
Alexandre Julliard883d3c52005-09-03 15:11:29 +0000316 * abort_thread
Alexandre Julliard85744122003-11-05 23:31:11 +0000317 */
Alexandre Julliard7e4c88c2005-09-13 11:07:14 +0000318static void DECLSPEC_NORETURN abort_thread( long status )
Alexandre Julliard85744122003-11-05 23:31:11 +0000319{
Alexandre Julliard85744122003-11-05 23:31:11 +0000320 _exit( status );
321}
322
323
Alexandre Julliard883d3c52005-09-03 15:11:29 +0000324/***********************************************************************
325 * pthread_functions
326 */
327const struct wine_pthread_functions pthread_functions =
328{
329 init_process,
330 init_thread,
331 create_thread,
332 init_current_teb,
333 get_current_teb,
334 exit_thread,
Alexandre Julliarde040e6c2006-06-23 12:27:45 +0200335 abort_thread,
336 sigprocmask
Alexandre Julliard883d3c52005-09-03 15:11:29 +0000337};
338
339
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000340/* Currently this probably works only for glibc2,
341 * which checks for the presence of double-underscore-prepended
342 * pthread primitives, and use them if available.
343 * If they are not available, the libc defaults to
344 * non-threadsafe operation (not good). */
345
Hans Leidekkercbaa5452004-10-19 03:57:05 +0000346#if defined(HAVE_PTHREAD_H) && (defined(__GLIBC__) || defined(__FreeBSD__))
Patrik Stridvall6caeb722002-11-25 21:12:26 +0000347
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000348/* adapt as necessary (a construct like this is used in glibc sources) */
349#define strong_alias(orig, alias) \
Ove Kaavend2937312000-05-09 22:32:25 +0000350 asm(".globl " PSTR(alias) "\n" \
351 "\t.set " PSTR(alias) "," PSTR(orig))
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000352
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000353struct fork_block;
354
Alexandre Julliard03d79982003-08-15 03:55:06 +0000355/* pthread functions redirection */
356
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000357struct pthread_functions
358{
359 pid_t (*ptr_pthread_fork) (struct fork_block *);
360 int (*ptr_pthread_attr_destroy) (pthread_attr_t *);
361 int (*ptr___pthread_attr_init_2_0) (pthread_attr_t *);
362 int (*ptr___pthread_attr_init_2_1) (pthread_attr_t *);
363 int (*ptr_pthread_attr_getdetachstate) (const pthread_attr_t *, int *);
364 int (*ptr_pthread_attr_setdetachstate) (pthread_attr_t *, int);
365 int (*ptr_pthread_attr_getinheritsched) (const pthread_attr_t *, int *);
366 int (*ptr_pthread_attr_setinheritsched) (pthread_attr_t *, int);
367 int (*ptr_pthread_attr_getschedparam) (const pthread_attr_t *, struct sched_param *);
368 int (*ptr_pthread_attr_setschedparam) (pthread_attr_t *, const struct sched_param *);
369 int (*ptr_pthread_attr_getschedpolicy) (const pthread_attr_t *, int *);
370 int (*ptr_pthread_attr_setschedpolicy) (pthread_attr_t *, int);
371 int (*ptr_pthread_attr_getscope) (const pthread_attr_t *, int *);
372 int (*ptr_pthread_attr_setscope) (pthread_attr_t *, int);
373 int (*ptr_pthread_condattr_destroy) (pthread_condattr_t *);
374 int (*ptr_pthread_condattr_init) (pthread_condattr_t *);
375 int (*ptr___pthread_cond_broadcast) (pthread_cond_t *);
376 int (*ptr___pthread_cond_destroy) (pthread_cond_t *);
377 int (*ptr___pthread_cond_init) (pthread_cond_t *, const pthread_condattr_t *);
378 int (*ptr___pthread_cond_signal) (pthread_cond_t *);
379 int (*ptr___pthread_cond_wait) (pthread_cond_t *, pthread_mutex_t *);
380 int (*ptr_pthread_equal) (pthread_t, pthread_t);
381 void (*ptr___pthread_exit) (void *);
382 int (*ptr_pthread_getschedparam) (pthread_t, int *, struct sched_param *);
383 int (*ptr_pthread_setschedparam) (pthread_t, int, const struct sched_param *);
384 int (*ptr_pthread_mutex_destroy) (pthread_mutex_t *);
385 int (*ptr_pthread_mutex_init) (pthread_mutex_t *, const pthread_mutexattr_t *);
386 int (*ptr_pthread_mutex_lock) (pthread_mutex_t *);
387 int (*ptr_pthread_mutex_trylock) (pthread_mutex_t *);
388 int (*ptr_pthread_mutex_unlock) (pthread_mutex_t *);
389 pthread_t (*ptr_pthread_self) (void);
390 int (*ptr_pthread_setcancelstate) (int, int *);
391 int (*ptr_pthread_setcanceltype) (int, int *);
392 void (*ptr_pthread_do_exit) (void *retval, char *currentframe);
393 void (*ptr_pthread_cleanup_upto) (jmp_buf target, char *targetframe);
394 pthread_descr (*ptr_pthread_thread_self) (void);
395 int (*ptr_pthread_internal_tsd_set) (int key, const void *pointer);
396 void * (*ptr_pthread_internal_tsd_get) (int key);
397 void ** __attribute__ ((__const__)) (*ptr_pthread_internal_tsd_address) (int key);
398 int (*ptr_pthread_sigaction) (int sig, const struct sigaction * act, struct sigaction *oact);
399 int (*ptr_pthread_sigwait) (const sigset_t *set, int *sig);
400 int (*ptr_pthread_raise) (int sig);
Alexandre Julliarddbb2b802003-09-11 01:09:09 +0000401 int (*ptr___pthread_cond_timedwait) (pthread_cond_t *, pthread_mutex_t *, const struct timespec *);
Alexandre Julliarde8bd1102003-10-03 03:39:29 +0000402 void (*ptr__pthread_cleanup_push) (struct _pthread_cleanup_buffer * buffer, void (*routine)(void *), void * arg);
403 void (*ptr__pthread_cleanup_pop) (struct _pthread_cleanup_buffer * buffer, int execute);
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000404};
405
Alexandre Julliard26fd7402002-10-22 00:44:24 +0000406static pid_t (*libc_fork)(void);
407static int (*libc_sigaction)(int signum, const struct sigaction *act, struct sigaction *oldact);
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000408static int *(*libc_pthread_init)( const struct pthread_functions *funcs );
Ove Kaaven1abdb6f2000-04-28 14:44:05 +0000409
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000410static struct pthread_functions libc_pthread_functions;
411
412strong_alias(__pthread_thread_self, pthread_thread_self);
Alexandre Julliard26fd7402002-10-22 00:44:24 +0000413
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000414/* redefine this to prevent libpthread from overriding our function pointers */
415int *__libc_pthread_init( const struct pthread_functions *funcs )
416{
417 return libc_multiple_threads;
418}
Ove Kaaven1abdb6f2000-04-28 14:44:05 +0000419
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000420typedef struct _wine_cleanup {
421 void (*routine)(void *);
422 void *arg;
423} *wine_cleanup;
424
Chris Morgan417296c2002-04-02 00:49:05 +0000425int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void*
426 (*start_routine)(void *), void* arg)
427{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000428 assert( funcs.ptr_pthread_create );
429 return funcs.ptr_pthread_create( thread, attr, start_routine, arg );
Chris Morgan417296c2002-04-02 00:49:05 +0000430}
Vincent Béron9a624912002-05-31 23:06:46 +0000431
Chris Morgan417296c2002-04-02 00:49:05 +0000432int pthread_cancel(pthread_t thread)
433{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000434 assert( funcs.ptr_pthread_cancel );
435 return funcs.ptr_pthread_cancel( thread );
Vincent Béron9a624912002-05-31 23:06:46 +0000436}
Chris Morgan417296c2002-04-02 00:49:05 +0000437
438int pthread_join(pthread_t thread, void **value_ptr)
439{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000440 assert( funcs.ptr_pthread_join );
441 return funcs.ptr_pthread_join( thread, value_ptr );
Vincent Béron9a624912002-05-31 23:06:46 +0000442}
Chris Morgan417296c2002-04-02 00:49:05 +0000443
Chris Morgan417296c2002-04-02 00:49:05 +0000444int pthread_detach(pthread_t thread)
445{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000446 assert( funcs.ptr_pthread_detach );
447 return funcs.ptr_pthread_detach( thread );
Chris Morgan417296c2002-04-02 00:49:05 +0000448}
449
450/* FIXME: we have no equivalents in win32 for the policys */
451/* so just keep this as a stub */
452int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
453{
454 P_OUTPUT("FIXME:pthread_attr_setschedpolicy\n");
455 return 0;
456}
457
458/* FIXME: no win32 equivalent for scope */
459int pthread_attr_setscope(pthread_attr_t *attr, int scope)
460{
461 P_OUTPUT("FIXME:pthread_attr_setscope\n");
462 return 0; /* return success */
463}
Vincent Béron9a624912002-05-31 23:06:46 +0000464
Chris Morgan417296c2002-04-02 00:49:05 +0000465/* FIXME: no win32 equivalent for schedule param */
466int pthread_attr_setschedparam(pthread_attr_t *attr,
467 const struct sched_param *param)
468{
469 P_OUTPUT("FIXME:pthread_attr_setschedparam\n");
470 return 0; /* return success */
471}
472
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000473/* FIXME */
474int pthread_attr_setstack(pthread_attr_t *attr, void *addr, size_t size)
475{
476 return 0; /* return success */
477}
478
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000479int __pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
480{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000481 static pthread_once_t the_once = PTHREAD_ONCE_INIT;
Alexandre Julliard43c63962005-09-26 13:51:58 +0000482 int once_now;
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000483
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000484 memcpy(&once_now,&the_once,sizeof(once_now));
Alexandre Julliard43c63962005-09-26 13:51:58 +0000485 if (interlocked_cmpxchg((int*)once_control, once_now+1, once_now) == once_now)
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000486 (*init_routine)();
487 return 0;
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000488}
489strong_alias(__pthread_once, pthread_once);
490
Ove Kaaven166209a2000-04-23 20:01:45 +0000491void __pthread_kill_other_threads_np(void)
492{
Alexandre Julliardde70b832001-10-09 21:59:16 +0000493 /* we don't need to do anything here */
Ove Kaaven166209a2000-04-23 20:01:45 +0000494}
495strong_alias(__pthread_kill_other_threads_np, pthread_kill_other_threads_np);
496
Alexandre Julliard95a43322000-05-01 16:19:40 +0000497/***** atfork *****/
498
499#define MAX_ATFORK 8 /* libc doesn't need that many anyway */
500
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000501static pthread_mutex_t atfork_mutex = PTHREAD_MUTEX_INITIALIZER;
Alexandre Julliard19b6a492003-08-12 23:50:54 +0000502
Eric Poueche66e2272006-02-06 13:13:28 +0100503typedef void (*atfork_handler)(void);
Alexandre Julliard95a43322000-05-01 16:19:40 +0000504static atfork_handler atfork_prepare[MAX_ATFORK];
505static atfork_handler atfork_parent[MAX_ATFORK];
506static atfork_handler atfork_child[MAX_ATFORK];
507static int atfork_count;
508
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000509int __pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
Ove Kaaven166209a2000-04-23 20:01:45 +0000510{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000511 pthread_mutex_lock( &atfork_mutex );
Alexandre Julliard95a43322000-05-01 16:19:40 +0000512 assert( atfork_count < MAX_ATFORK );
513 atfork_prepare[atfork_count] = prepare;
514 atfork_parent[atfork_count] = parent;
515 atfork_child[atfork_count] = child;
516 atfork_count++;
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000517 pthread_mutex_unlock( &atfork_mutex );
Alexandre Julliard95a43322000-05-01 16:19:40 +0000518 return 0;
Ove Kaaven166209a2000-04-23 20:01:45 +0000519}
520strong_alias(__pthread_atfork, pthread_atfork);
521
Alexandre Julliard26fd7402002-10-22 00:44:24 +0000522pid_t __fork(void)
Ove Kaaven1abdb6f2000-04-28 14:44:05 +0000523{
Alexandre Julliard95a43322000-05-01 16:19:40 +0000524 pid_t pid;
525 int i;
526
Alexandre Julliard26fd7402002-10-22 00:44:24 +0000527 if (!libc_fork)
528 {
Alexandre Julliard9bfe0c42004-06-24 04:07:22 +0000529 libc_fork = wine_dlsym( RTLD_NEXT, "fork", NULL, 0 );
Alexandre Julliard26fd7402002-10-22 00:44:24 +0000530 assert( libc_fork );
531 }
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000532 pthread_mutex_lock( &atfork_mutex );
Alexandre Julliard95a43322000-05-01 16:19:40 +0000533 /* prepare handlers are called in reverse insertion order */
Bill Medland7a60dd02001-09-26 23:04:40 +0000534 for (i = atfork_count - 1; i >= 0; i--) if (atfork_prepare[i]) atfork_prepare[i]();
Alexandre Julliard26fd7402002-10-22 00:44:24 +0000535 if (!(pid = libc_fork()))
Alexandre Julliard95a43322000-05-01 16:19:40 +0000536 {
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000537 pthread_mutex_init( &atfork_mutex, NULL );
Bill Medland7a60dd02001-09-26 23:04:40 +0000538 for (i = 0; i < atfork_count; i++) if (atfork_child[i]) atfork_child[i]();
Alexandre Julliard95a43322000-05-01 16:19:40 +0000539 }
540 else
541 {
Bill Medland7a60dd02001-09-26 23:04:40 +0000542 for (i = 0; i < atfork_count; i++) if (atfork_parent[i]) atfork_parent[i]();
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000543 pthread_mutex_unlock( &atfork_mutex );
Alexandre Julliard95a43322000-05-01 16:19:40 +0000544 }
545 return pid;
Ove Kaaven1abdb6f2000-04-28 14:44:05 +0000546}
Alexandre Julliard26fd7402002-10-22 00:44:24 +0000547strong_alias(__fork, fork);
Ove Kaaven166209a2000-04-23 20:01:45 +0000548
549/***** MUTEXES *****/
550
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000551int __pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000552{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000553 if (!funcs.ptr_pthread_mutex_init) return 0;
554 return funcs.ptr_pthread_mutex_init( mutex, mutexattr );
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000555}
556strong_alias(__pthread_mutex_init, pthread_mutex_init);
557
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000558int __pthread_mutex_lock(pthread_mutex_t *mutex)
559{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000560 if (!funcs.ptr_pthread_mutex_lock) return 0;
561 return funcs.ptr_pthread_mutex_lock( mutex );
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000562}
563strong_alias(__pthread_mutex_lock, pthread_mutex_lock);
564
565int __pthread_mutex_trylock(pthread_mutex_t *mutex)
566{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000567 if (!funcs.ptr_pthread_mutex_trylock) return 0;
568 return funcs.ptr_pthread_mutex_trylock( mutex );
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000569}
570strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock);
571
572int __pthread_mutex_unlock(pthread_mutex_t *mutex)
573{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000574 if (!funcs.ptr_pthread_mutex_unlock) return 0;
575 return funcs.ptr_pthread_mutex_unlock( mutex );
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000576}
577strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock);
578
579int __pthread_mutex_destroy(pthread_mutex_t *mutex)
580{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000581 if (!funcs.ptr_pthread_mutex_destroy) return 0;
582 return funcs.ptr_pthread_mutex_destroy( mutex );
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000583}
584strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy);
585
Ove Kaaven166209a2000-04-23 20:01:45 +0000586
587/***** MUTEX ATTRIBUTES *****/
588/* just dummies, since critical sections are always recursive */
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000589
590int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
591{
592 return 0;
593}
594strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init);
595
596int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
597{
598 return 0;
599}
600strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy);
601
602int __pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind)
603{
604 return 0;
605}
606strong_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np);
607
608int __pthread_mutexattr_getkind_np(pthread_mutexattr_t *attr, int *kind)
609{
Patrik Stridvall6caeb722002-11-25 21:12:26 +0000610 *kind = PTHREAD_MUTEX_RECURSIVE;
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000611 return 0;
612}
613strong_alias(__pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np);
614
615int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind)
616{
617 return 0;
618}
619strong_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype);
620
Vincent Bérond17c1622004-10-18 19:33:16 +0000621int __pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *kind)
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000622{
Patrik Stridvall6caeb722002-11-25 21:12:26 +0000623 *kind = PTHREAD_MUTEX_RECURSIVE;
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000624 return 0;
625}
626strong_alias(__pthread_mutexattr_gettype, pthread_mutexattr_gettype);
627
Ove Kaaven166209a2000-04-23 20:01:45 +0000628
629/***** THREAD-SPECIFIC VARIABLES (KEYS) *****/
630
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000631int __pthread_key_create(pthread_key_t *key, void (*destr_function)(void *))
632{
Alexandre Julliard43c63962005-09-26 13:51:58 +0000633 static int keycnt = FIRST_KEY;
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000634 *key = interlocked_xchg_add(&keycnt, 1);
635 return 0;
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000636}
637strong_alias(__pthread_key_create, pthread_key_create);
638
639int __pthread_key_delete(pthread_key_t key)
640{
641 return 0;
642}
643strong_alias(__pthread_key_delete, pthread_key_delete);
644
645int __pthread_setspecific(pthread_key_t key, const void *pointer)
646{
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000647 pthread_descr descr = __pthread_thread_self();
648 descr->key_data[key] = pointer;
649 return 0;
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000650}
651strong_alias(__pthread_setspecific, pthread_setspecific);
652
653void *__pthread_getspecific(pthread_key_t key)
654{
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000655 pthread_descr descr = __pthread_thread_self();
656 return (void *)descr->key_data[key];
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000657}
658strong_alias(__pthread_getspecific, pthread_getspecific);
659
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000660static int pthread_internal_tsd_set( int key, const void *pointer )
661{
662 pthread_descr descr = __pthread_thread_self();
663 descr->tsd_data[key] = pointer;
664 return 0;
665}
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000666int (*__libc_internal_tsd_set)(int, const void *) = pthread_internal_tsd_set;
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000667
668static void *pthread_internal_tsd_get( int key )
669{
670 pthread_descr descr = __pthread_thread_self();
671 return (void *)descr->tsd_data[key];
672}
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000673void* (*__libc_internal_tsd_get)(int) = pthread_internal_tsd_get;
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000674
675static void ** __attribute__((const)) pthread_internal_tsd_address( int key )
676{
677 pthread_descr descr = __pthread_thread_self();
678 return (void **)&descr->tsd_data[key];
679}
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000680void** (*__libc_internal_tsd_address)(int) = pthread_internal_tsd_address;
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000681
Ove Kaaven166209a2000-04-23 20:01:45 +0000682/***** "EXCEPTION" FRAMES *****/
683/* not implemented right now */
684
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000685void _pthread_cleanup_push(struct _pthread_cleanup_buffer *buffer, void (*routine)(void *), void *arg)
686{
687 ((wine_cleanup)buffer)->routine = routine;
688 ((wine_cleanup)buffer)->arg = arg;
689}
690
691void _pthread_cleanup_pop(struct _pthread_cleanup_buffer *buffer, int execute)
692{
693 if (execute) (*(((wine_cleanup)buffer)->routine))(((wine_cleanup)buffer)->arg);
694}
695
696void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer *buffer, void (*routine)(void *), void *arg)
697{
698 _pthread_cleanup_push(buffer, routine, arg);
699}
700
701void _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer *buffer, int execute)
702{
703 _pthread_cleanup_pop(buffer, execute);
704}
705
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000706void __pthread_cleanup_upto(jmp_buf target, char *frame)
707{
708 /* FIXME */
709}
Ove Kaaven166209a2000-04-23 20:01:45 +0000710
711/***** CONDITIONS *****/
Ove Kaaven166209a2000-04-23 20:01:45 +0000712
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000713int __pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
Ove Kaaven166209a2000-04-23 20:01:45 +0000714{
Alexandre Julliard3bff2b32003-09-23 22:59:44 +0000715 if (!funcs.ptr_pthread_cond_init) return 0;
716 return funcs.ptr_pthread_cond_init(cond, cond_attr);
Ove Kaaven166209a2000-04-23 20:01:45 +0000717}
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000718strong_alias(__pthread_cond_init, pthread_cond_init);
Ove Kaaven166209a2000-04-23 20:01:45 +0000719
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000720int __pthread_cond_destroy(pthread_cond_t *cond)
Ove Kaaven166209a2000-04-23 20:01:45 +0000721{
Alexandre Julliard3bff2b32003-09-23 22:59:44 +0000722 if (!funcs.ptr_pthread_cond_destroy) return 0;
723 return funcs.ptr_pthread_cond_destroy(cond);
Ove Kaaven166209a2000-04-23 20:01:45 +0000724}
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000725strong_alias(__pthread_cond_destroy, pthread_cond_destroy);
Ove Kaaven166209a2000-04-23 20:01:45 +0000726
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000727int __pthread_cond_signal(pthread_cond_t *cond)
Ove Kaaven166209a2000-04-23 20:01:45 +0000728{
Alexandre Julliard3bff2b32003-09-23 22:59:44 +0000729 if (!funcs.ptr_pthread_cond_signal) return 0;
730 return funcs.ptr_pthread_cond_signal(cond);
Ove Kaaven166209a2000-04-23 20:01:45 +0000731}
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000732strong_alias(__pthread_cond_signal, pthread_cond_signal);
Ove Kaaven166209a2000-04-23 20:01:45 +0000733
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000734int __pthread_cond_broadcast(pthread_cond_t *cond)
Ove Kaaven166209a2000-04-23 20:01:45 +0000735{
Alexandre Julliard3bff2b32003-09-23 22:59:44 +0000736 if (!funcs.ptr_pthread_cond_broadcast) return 0;
737 return funcs.ptr_pthread_cond_broadcast(cond);
Ove Kaaven166209a2000-04-23 20:01:45 +0000738}
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000739strong_alias(__pthread_cond_broadcast, pthread_cond_broadcast);
Ove Kaaven166209a2000-04-23 20:01:45 +0000740
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000741int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
Ove Kaaven166209a2000-04-23 20:01:45 +0000742{
Alexandre Julliard3bff2b32003-09-23 22:59:44 +0000743 if (!funcs.ptr_pthread_cond_wait) return 0;
744 return funcs.ptr_pthread_cond_wait(cond, mutex);
Ove Kaaven166209a2000-04-23 20:01:45 +0000745}
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000746strong_alias(__pthread_cond_wait, pthread_cond_wait);
Ove Kaaven166209a2000-04-23 20:01:45 +0000747
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000748int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
Ove Kaaven166209a2000-04-23 20:01:45 +0000749{
Alexandre Julliard3bff2b32003-09-23 22:59:44 +0000750 if (!funcs.ptr_pthread_cond_timedwait) return 0;
751 return funcs.ptr_pthread_cond_timedwait(cond, mutex, abstime);
Ove Kaaven166209a2000-04-23 20:01:45 +0000752}
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000753strong_alias(__pthread_cond_timedwait, pthread_cond_timedwait);
Ove Kaaven166209a2000-04-23 20:01:45 +0000754
755/**** CONDITION ATTRIBUTES *****/
756/* not implemented right now */
757
758int pthread_condattr_init(pthread_condattr_t *attr)
759{
760 return 0;
761}
762
763int pthread_condattr_destroy(pthread_condattr_t *attr)
764{
765 return 0;
766}
767
Ove Kaavenccc538b2000-11-13 04:14:49 +0000768/***** READ-WRITE LOCKS *****/
Jukka Heinonen31b8b642001-12-11 00:20:18 +0000769
Ove Kaavenccc538b2000-11-13 04:14:49 +0000770int __pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *rwlock_attr)
771{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000772 assert( funcs.ptr_pthread_rwlock_init );
773 return funcs.ptr_pthread_rwlock_init( rwlock, rwlock_attr );
Ove Kaavenccc538b2000-11-13 04:14:49 +0000774}
775strong_alias(__pthread_rwlock_init, pthread_rwlock_init);
776
777int __pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
778{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000779 assert( funcs.ptr_pthread_rwlock_destroy );
780 return funcs.ptr_pthread_rwlock_destroy( rwlock );
Ove Kaavenccc538b2000-11-13 04:14:49 +0000781}
782strong_alias(__pthread_rwlock_destroy, pthread_rwlock_destroy);
783
784int __pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
785{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000786 if (!funcs.ptr_pthread_rwlock_rdlock) return 0;
787 return funcs.ptr_pthread_rwlock_rdlock( rwlock );
Ove Kaavenccc538b2000-11-13 04:14:49 +0000788}
789strong_alias(__pthread_rwlock_rdlock, pthread_rwlock_rdlock);
790
791int __pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
792{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000793 assert( funcs.ptr_pthread_rwlock_tryrdlock );
794 return funcs.ptr_pthread_rwlock_tryrdlock( rwlock );
Ove Kaavenccc538b2000-11-13 04:14:49 +0000795}
796strong_alias(__pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock);
797
798int __pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
799{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000800 assert( funcs.ptr_pthread_rwlock_wrlock );
801 return funcs.ptr_pthread_rwlock_wrlock( rwlock );
Ove Kaavenccc538b2000-11-13 04:14:49 +0000802}
803strong_alias(__pthread_rwlock_wrlock, pthread_rwlock_wrlock);
804
805int __pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
806{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000807 assert( funcs.ptr_pthread_rwlock_trywrlock );
808 return funcs.ptr_pthread_rwlock_trywrlock( rwlock );
Ove Kaavenccc538b2000-11-13 04:14:49 +0000809}
810strong_alias(__pthread_rwlock_trywrlock, pthread_rwlock_trywrlock);
811
812int __pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
813{
Alexandre Julliard1d2eb372003-09-25 20:30:18 +0000814 if (!funcs.ptr_pthread_rwlock_unlock) return 0;
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000815 return funcs.ptr_pthread_rwlock_unlock( rwlock );
Ove Kaavenccc538b2000-11-13 04:14:49 +0000816}
817strong_alias(__pthread_rwlock_unlock, pthread_rwlock_unlock);
818
819/**** READ-WRITE LOCK ATTRIBUTES *****/
820/* not implemented right now */
821
822int pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
823{
824 return 0;
825}
826
827int __pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
828{
829 return 0;
830}
831strong_alias(__pthread_rwlockattr_destroy, pthread_rwlockattr_destroy);
832
833int pthread_rwlockattr_getkind_np(const pthread_rwlockattr_t *attr, int *pref)
834{
835 *pref = 0;
836 return 0;
837}
838
839int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *attr, int pref)
840{
841 return 0;
842}
Ove Kaavenccc538b2000-11-13 04:14:49 +0000843
Ove Kaaven166209a2000-04-23 20:01:45 +0000844/***** MISC *****/
845
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000846pthread_t pthread_self(void)
847{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000848 assert( funcs.ptr_pthread_self );
849 return funcs.ptr_pthread_self();
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000850}
851
852int pthread_equal(pthread_t thread1, pthread_t thread2)
853{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000854 assert( funcs.ptr_pthread_equal );
855 return funcs.ptr_pthread_equal( thread1, thread2 );
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000856}
857
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000858void __pthread_do_exit(void *retval, char *currentframe)
Ove Kaaven166209a2000-04-23 20:01:45 +0000859{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000860 assert( funcs.ptr_pthread_exit );
861 return funcs.ptr_pthread_exit( retval, currentframe );
Ove Kaaven166209a2000-04-23 20:01:45 +0000862}
863
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000864void __pthread_exit(void *retval)
865{
866 __pthread_do_exit( retval, NULL );
867}
868strong_alias(__pthread_exit, pthread_exit);
869
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000870int pthread_setcancelstate(int state, int *oldstate)
871{
872 pthread_descr descr = __pthread_thread_self();
873 if (oldstate) *oldstate = descr->cancel_state;
874 descr->cancel_state = state;
875 return 0;
876}
877
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000878int pthread_setcanceltype(int type, int *oldtype)
879{
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000880 pthread_descr descr = __pthread_thread_self();
881 if (oldtype) *oldtype = descr->cancel_type;
882 descr->cancel_type = type;
883 return 0;
Ove Kaavenf19f07d2000-04-14 14:47:02 +0000884}
885
Ove Kaaven166209a2000-04-23 20:01:45 +0000886/***** ANTI-OVERRIDES *****/
887/* pthreads tries to override these, point them back to libc */
888
Ove Kaaven166209a2000-04-23 20:01:45 +0000889int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
890{
Alexandre Julliard26fd7402002-10-22 00:44:24 +0000891 if (!libc_sigaction)
892 {
Alexandre Julliard9bfe0c42004-06-24 04:07:22 +0000893 libc_sigaction = wine_dlsym( RTLD_NEXT, "sigaction", NULL, 0 );
Alexandre Julliard26fd7402002-10-22 00:44:24 +0000894 assert( libc_sigaction );
895 }
896 return libc_sigaction(signum, act, oldact);
Ove Kaaven166209a2000-04-23 20:01:45 +0000897}
Alexandre Julliard26fd7402002-10-22 00:44:24 +0000898
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000899void __pthread_initialize(void)
900{
901 static int done;
902
903 if (!done)
904 {
905 done = 1;
Alexandre Julliard959113d2006-12-20 17:03:23 +0100906 /* check for exported epoll_create to detect glibc versions that we cannot support */
907 if (wine_dlsym( RTLD_DEFAULT, "epoll_create", NULL, 0 ))
908 {
909 static const char warning[] =
910 "wine: glibc >= 2.3 without NPTL or TLS is not a supported combination.\n"
911 " It will most likely crash. Please upgrade to a glibc with NPTL support.\n";
912 write( 2, warning, sizeof(warning)-1 );
913 }
Alexandre Julliard9bfe0c42004-06-24 04:07:22 +0000914 libc_fork = wine_dlsym( RTLD_NEXT, "fork", NULL, 0 );
915 libc_sigaction = wine_dlsym( RTLD_NEXT, "sigaction", NULL, 0 );
916 libc_uselocale = wine_dlsym( RTLD_DEFAULT, "uselocale", NULL, 0 );
917 libc_pthread_init = wine_dlsym( RTLD_NEXT, "__libc_pthread_init", NULL, 0 );
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000918 if (libc_pthread_init) libc_multiple_threads = libc_pthread_init( &libc_pthread_functions );
919 }
920}
Alexandre Julliardcfe45cc2006-01-14 17:08:52 +0100921
922#ifdef __GNUC__
923static void init(void) __attribute__((constructor));
924static void init(void)
925{
926 __pthread_initialize();
927}
928#endif
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000929
930static struct pthread_functions libc_pthread_functions =
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000931{
932 NULL, /* ptr_pthread_fork */
933 NULL, /* FIXME */ /* ptr_pthread_attr_destroy */
934 NULL, /* FIXME */ /* ptr___pthread_attr_init_2_0 */
935 NULL, /* FIXME */ /* ptr___pthread_attr_init_2_1 */
936 NULL, /* FIXME */ /* ptr_pthread_attr_getdetachstate */
937 NULL, /* FIXME */ /* ptr_pthread_attr_setdetachstate */
938 NULL, /* FIXME */ /* ptr_pthread_attr_getinheritsched */
939 NULL, /* FIXME */ /* ptr_pthread_attr_setinheritsched */
940 NULL, /* FIXME */ /* ptr_pthread_attr_getschedparam */
941 pthread_attr_setschedparam, /* ptr_pthread_attr_setschedparam */
Alexandre Julliardf45325e2003-11-06 23:05:41 +0000942 NULL, /* FIXME */ /* ptr_pthread_attr_getschedpolicy */
943 NULL, /* FIXME */ /* ptr_pthread_attr_setschedpolicy */
944 NULL, /* FIXME */ /* ptr_pthread_attr_getscope */
945 NULL, /* FIXME */ /* ptr_pthread_attr_setscope */
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000946 pthread_condattr_destroy, /* ptr_pthread_condattr_destroy */
947 pthread_condattr_init, /* ptr_pthread_condattr_init */
948 __pthread_cond_broadcast, /* ptr___pthread_cond_broadcast */
949 __pthread_cond_destroy, /* ptr___pthread_cond_destroy */
950 __pthread_cond_init, /* ptr___pthread_cond_init */
951 __pthread_cond_signal, /* ptr___pthread_cond_signal */
952 __pthread_cond_wait, /* ptr___pthread_cond_wait */
953 pthread_equal, /* ptr_pthread_equal */
954 __pthread_exit, /* ptr___pthread_exit */
955 NULL, /* FIXME */ /* ptr_pthread_getschedparam */
956 NULL, /* FIXME */ /* ptr_pthread_setschedparam */
957 __pthread_mutex_destroy, /* ptr_pthread_mutex_destroy */
958 __pthread_mutex_init, /* ptr_pthread_mutex_init */
959 __pthread_mutex_lock, /* ptr_pthread_mutex_lock */
960 __pthread_mutex_trylock, /* ptr_pthread_mutex_trylock */
961 __pthread_mutex_unlock, /* ptr_pthread_mutex_unlock */
962 pthread_self, /* ptr_pthread_self */
Alexandre Julliard80e34db2003-09-03 00:26:08 +0000963 pthread_setcancelstate, /* ptr_pthread_setcancelstate */
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000964 pthread_setcanceltype, /* ptr_pthread_setcanceltype */
965 __pthread_do_exit, /* ptr_pthread_do_exit */
966 __pthread_cleanup_upto, /* ptr_pthread_cleanup_upto */
967 __pthread_thread_self, /* ptr_pthread_thread_self */
968 pthread_internal_tsd_set, /* ptr_pthread_internal_tsd_set */
969 pthread_internal_tsd_get, /* ptr_pthread_internal_tsd_get */
970 pthread_internal_tsd_address, /* ptr_pthread_internal_tsd_address */
971 NULL, /* ptr_pthread_sigaction */
972 NULL, /* ptr_pthread_sigwait */
Alexandre Julliarddbb2b802003-09-11 01:09:09 +0000973 NULL, /* ptr_pthread_raise */
Alexandre Julliarde8bd1102003-10-03 03:39:29 +0000974 __pthread_cond_timedwait, /* ptr___pthread_cond_timedwait */
975 _pthread_cleanup_push, /* ptr__pthread_cleanup_push */
976 _pthread_cleanup_pop /* ptr__pthread_cleanup_pop */
Alexandre Julliard97d862c2003-08-12 18:59:13 +0000977};
978
Hans Leidekkercbaa5452004-10-19 03:57:05 +0000979#endif /* HAVE_PTHREAD_H && (__GLIBC__ || __FREEBSD__) */