From 0e446d5912567efdef6cd9b2f7d23e77f7622cb9 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 2 Mar 2009 12:29:32 +0100 Subject: [PATCH] loader: Get rid of the no longer supported wine-kthread. --- .gitignore | 2 - configure | 6 +- configure.ac | 4 +- include/config.h.in | 6 - loader/Makefile.in | 10 - loader/glibc.c | 17 +- loader/kthread.c | 975 -------------------------------------------- 7 files changed, 9 insertions(+), 1011 deletions(-) delete mode 100644 loader/kthread.c diff --git a/.gitignore b/.gitignore index 5bbd4d09bfa..868b7859bdf 100644 --- a/.gitignore +++ b/.gitignore @@ -215,8 +215,6 @@ loader/wine-freebsd loader/wine-freebsd-installed loader/wine-glibc loader/wine-glibc-installed -loader/wine-kthread -loader/wine-kthread-installed loader/wine-preloader loader/wine-preloader-installed loader/wine-pthread diff --git a/configure b/configure index 21712a801cc..33a4bc1806e 100755 --- a/configure +++ b/configure @@ -17906,7 +17906,7 @@ MAIN_BINARY="wine-pthread" linux* | k*bsd*-gnu) MAIN_BINARY="wine-glibc" - EXTRA_BINARIES="wine-kthread wine-pthread wine-preloader" + EXTRA_BINARIES="wine-pthread wine-preloader" ;; freebsd*) MAIN_BINARY="wine-freebsd" @@ -17988,8 +17988,6 @@ CFLAGS="$CFLAGS $BUILTINFLAG" - - @@ -18006,7 +18004,6 @@ for ac_func in \ _vsnprintf \ asctime_r \ chsize \ - clone \ dlopen \ epoll_create \ ffs \ @@ -18039,7 +18036,6 @@ for ac_func in \ pwrite \ readdir \ readlink \ - rfork \ sched_yield \ select \ setproctitle \ diff --git a/configure.ac b/configure.ac index c88343055ce..4d5a235df20 100644 --- a/configure.ac +++ b/configure.ac @@ -1417,7 +1417,7 @@ case $host_cpu in case $host_os in linux* | k*bsd*-gnu) AC_SUBST(MAIN_BINARY,"wine-glibc") - AC_SUBST(EXTRA_BINARIES,"wine-kthread wine-pthread wine-preloader") ;; + AC_SUBST(EXTRA_BINARIES,"wine-pthread wine-preloader") ;; freebsd*) AC_SUBST(MAIN_BINARY,"wine-freebsd") AC_SUBST(EXTRA_BINARIES,"wine-pthread") ;; @@ -1442,7 +1442,6 @@ AC_CHECK_FUNCS(\ _vsnprintf \ asctime_r \ chsize \ - clone \ dlopen \ epoll_create \ ffs \ @@ -1475,7 +1474,6 @@ AC_CHECK_FUNCS(\ pwrite \ readdir \ readlink \ - rfork \ sched_yield \ select \ setproctitle \ diff --git a/include/config.h.in b/include/config.h.in index f1c4194b535..575bb8ee3b0 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -41,9 +41,6 @@ /* Define to 1 if you have the `chsize' function. */ #undef HAVE_CHSIZE -/* Define to 1 if you have the `clone' function. */ -#undef HAVE_CLONE - /* Define to 1 if you have the header file. */ #undef HAVE_COREAUDIO_COREAUDIO_H @@ -606,9 +603,6 @@ /* Define to 1 if you have the header file. */ #undef HAVE_RESOLV_H -/* Define to 1 if you have the `rfork' function. */ -#undef HAVE_RFORK - /* Define to 1 if you have the header file. */ #undef HAVE_SCHED_H diff --git a/loader/Makefile.in b/loader/Makefile.in index 3f207ee78b4..23bf99e8c9c 100644 --- a/loader/Makefile.in +++ b/loader/Makefile.in @@ -7,12 +7,10 @@ MODULE = wine C_SRCS = \ freebsd.c \ glibc.c \ - kthread.c \ main.c \ preloader.c \ pthread.c -KTHREAD_OBJS = kthread.o main.o PTHREAD_OBJS = pthread.o main.o MAIN_BINARY = @MAIN_BINARY@ @@ -25,8 +23,6 @@ PROGRAMS = \ wine-freebsd-installed \ wine-glibc \ wine-glibc-installed \ - wine-kthread \ - wine-kthread-installed \ wine-preloader \ wine-preloader-installed \ wine-pthread \ @@ -65,12 +61,6 @@ wine-glibc-installed: glibc.o Makefile.in wine-preloader wine-preloader-installed: preloader.o Makefile.in $(CC) -o $@ -static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x7c000000 preloader.o $(LIBPORT) $(LDFLAGS) -wine-kthread: $(KTHREAD_OBJS) Makefile.in - $(CC) -o $@ $(LDEXECFLAGS) $(KTHREAD_OBJS) $(LIBWINE) $(LIBPORT) $(EXTRALIBS) $(LDFLAGS) $(LDRPATH_LOCAL) - -wine-kthread-installed: $(KTHREAD_OBJS) Makefile.in - $(CC) -o $@ $(LDEXECFLAGS) $(KTHREAD_OBJS) $(LIBWINE) $(LIBPORT) $(EXTRALIBS) $(LDFLAGS) $(LDRPATH_INSTALL) - wine-pthread: $(PTHREAD_OBJS) Makefile.in $(CC) -o $@ $(LDEXECFLAGS) $(PTHREAD_OBJS) $(LIBWINE) $(LIBPORT) $(LIBPTHREAD) $(EXTRALIBS) $(LDFLAGS) $(LDRPATH_LOCAL) diff --git a/loader/glibc.c b/loader/glibc.c index e312cf31717..1a1829680b6 100644 --- a/loader/glibc.c +++ b/loader/glibc.c @@ -56,7 +56,6 @@ static void *xmalloc( size_t size ) /* separate thread to check for NPTL and TLS features */ static void *needs_pthread( void *arg ) { - const char *loader; pid_t tid = gettid(); /* check for NPTL */ if (tid != -1 && tid != getpid()) return (void *)1; @@ -70,20 +69,18 @@ static void *needs_pthread( void *arg ) else fprintf( stderr, "wine: Your C library is too old. You need at least glibc 2.3 with NPTL support.\n" ); - if (!(loader = getenv( "WINELOADER" )) || !strstr( loader, "wine-kthread" )) - exit(1); return 0; } -/* return the name of the Wine threading variant to use */ -static const char *get_threading(void) +/* check if we support the glibc threading model */ +static void check_threading(void) { pthread_t id; void *ret; pthread_create( &id, NULL, needs_pthread, NULL ); pthread_join( id, &ret ); - return ret ? "wine-pthread" : "wine-kthread"; + if (!ret) exit(1); } /* build a new full path from the specified path and name */ @@ -130,8 +127,7 @@ static void set_max_limit( int limit ) int main( int argc, char *argv[] ) { const char *loader = getenv( "WINELOADER" ); - const char *threads = get_threading(); - const char *new_argv0 = build_new_path( argv[0], threads ); + const char *new_argv0 = build_new_path( argv[0], "wine-pthread" ); wine_init_argv0_path( new_argv0 ); @@ -141,7 +137,7 @@ int main( int argc, char *argv[] ) if (loader) { /* update WINELOADER with the new name */ - const char *new_name = build_new_path( loader, threads ); + const char *new_name = build_new_path( loader, "wine-pthread" ); char *new_loader = xmalloc( sizeof("WINELOADER=") + strlen(new_name) ); strcpy( new_loader, "WINELOADER=" ); strcat( new_loader, new_name ); @@ -149,8 +145,9 @@ int main( int argc, char *argv[] ) loader = new_name; } + check_threading(); check_vmsplit( &argc ); wine_exec_wine_binary( NULL, argv, loader ); - fprintf( stderr, "wine: could not exec %s\n", threads ); + fprintf( stderr, "wine: could not exec wine-pthread\n" ); exit(1); } diff --git a/loader/kthread.c b/loader/kthread.c deleted file mode 100644 index fcdd34db67f..00000000000 --- a/loader/kthread.c +++ /dev/null @@ -1,975 +0,0 @@ -/* - * pthread emulation based on kernel threads - * - * We can't use pthreads directly, so why not let libcs - * that want pthreads use Wine's own threading instead... - * - * Copyright 1999 Ove Kåven - * Copyright 2003 Alexandre Julliard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "config.h" -#include "wine/port.h" - -struct _pthread_cleanup_buffer; - -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#include -#include -#ifdef HAVE_SYS_SOCKET_H -# include -#endif -#ifdef HAVE_SYS_MMAN_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -# include -#endif -#ifdef HAVE_ARPA_NAMESER_H -# include -#endif -#ifdef HAVE_RESOLV_H -# include -#endif -#ifdef HAVE_VALGRIND_VALGRIND_H -#include -#endif -#ifdef HAVE_SYS_SYSCALL_H -# include -#endif -#ifdef HAVE_SCHED_H -#include -#endif - -#include "wine/library.h" -#include "wine/pthread.h" - -#define P_OUTPUT(stuff) write(2,stuff,strlen(stuff)) - -#define PSTR(str) __ASM_NAME(#str) - -static struct wine_pthread_callbacks funcs; - -/* thread descriptor */ - -#define FIRST_KEY 0 -#define MAX_KEYS 16 /* libc6 doesn't use that many, but... */ -#define MAX_TSD 16 - -struct pthread_descr_struct -{ - char dummy[2048]; - int thread_errno; - int thread_h_errno; - int cancel_state; - int cancel_type; - struct __res_state res_state; - const void *key_data[MAX_KEYS]; /* for normal pthread keys */ - const void *tsd_data[MAX_TSD]; /* for libc internal tsd variables */ -}; - -typedef struct pthread_descr_struct *pthread_descr; - -static struct pthread_descr_struct initial_descr; - -pthread_descr __pthread_thread_self(void) -{ - struct pthread_descr_struct *descr; - if (!funcs.ptr_get_thread_data) return &initial_descr; - descr = funcs.ptr_get_thread_data(); - if (!descr) return &initial_descr; - return descr; -} - -static int (*libc_uselocale)(int set); -static int *libc_multiple_threads; - -/*********************************************************************** - * __errno_location/__error/__errno/___errno/__thr_errno - * - * Get the per-thread errno location. - */ -int *__errno_location(void) /* Linux */ -{ - pthread_descr descr = __pthread_thread_self(); - return &descr->thread_errno; -} -int *__error(void) { return __errno_location(); } /* FreeBSD */ -int *__errno(void) { return __errno_location(); } /* NetBSD */ -int *___errno(void) { return __errno_location(); } /* Solaris */ -int *__thr_errno(void) { return __errno_location(); } /* UnixWare */ - -/*********************************************************************** - * __h_errno_location - * - * Get the per-thread h_errno location. - */ -int *__h_errno_location(void) -{ - pthread_descr descr = __pthread_thread_self(); - return &descr->thread_h_errno; -} - -struct __res_state *__res_state(void) -{ - pthread_descr descr = __pthread_thread_self(); - return &descr->res_state; -} - -static inline void writejump( const char *symbol, void *dest ) -{ -#if defined(__GLIBC__) && defined(__i386__) - unsigned char *addr = wine_dlsym( RTLD_NEXT, symbol, NULL, 0 ); - - if (!addr) return; - - /* write a relative jump at the function address */ - mprotect((void*)((unsigned int)addr & ~(getpagesize()-1)), 5, PROT_READ|PROT_EXEC|PROT_WRITE); - addr[0] = 0xe9; - *(int *)(addr+1) = (unsigned char *)dest - (addr + 5); - mprotect((void*)((unsigned int)addr & ~(getpagesize()-1)), 5, PROT_READ|PROT_EXEC); - -# ifdef VALGRIND_DISCARD_TRANSLATIONS - VALGRIND_DISCARD_TRANSLATIONS( addr, 5 ); -# endif -#endif /* __GLIBC__ && __i386__ */ -} - -/* temporary stacks used on thread exit */ -#define TEMP_STACK_SIZE 1024 -#define NB_TEMP_STACKS 8 -static char temp_stacks[NB_TEMP_STACKS][TEMP_STACK_SIZE]; -static int next_temp_stack; /* next temp stack to use */ - -/*********************************************************************** - * get_temp_stack - * - * Get a temporary stack address to run the thread exit code on. - */ -static inline char *get_temp_stack(void) -{ - unsigned int next = interlocked_xchg_add( &next_temp_stack, 1 ); - return temp_stacks[next % NB_TEMP_STACKS] + TEMP_STACK_SIZE; -} - - -/*********************************************************************** - * cleanup_thread - * - * Cleanup the remains of a thread. Runs on a temporary stack. - */ -static void cleanup_thread( void *ptr ) -{ - /* copy the info structure since it is on the stack we will free */ - struct wine_pthread_thread_info info = *(struct wine_pthread_thread_info *)ptr; - wine_ldt_free_fs( info.teb_sel ); - if (info.stack_size) munmap( info.stack_base, info.stack_size ); - if (info.teb_size) munmap( info.teb_base, info.teb_size ); - _exit( info.exit_status ); -} - - -/*********************************************************************** - * init_process - * - * Initialization for a newly created process. - */ -static void init_process( const struct wine_pthread_callbacks *callbacks, size_t size ) -{ - memcpy( &funcs, callbacks, min( size, sizeof(funcs) )); - funcs.ptr_set_thread_data( &initial_descr ); -} - - -/*********************************************************************** - * init_thread - * - * Initialization for a newly created thread. - */ -static void init_thread( struct wine_pthread_thread_info *info ) -{ - struct pthread_descr_struct *descr; - - if (funcs.ptr_set_thread_data) - { - descr = calloc( 1, sizeof(*descr) ); - funcs.ptr_set_thread_data( descr ); - if (libc_multiple_threads) *libc_multiple_threads = 1; - } - else /* first thread */ - { - descr = &initial_descr; - writejump( "__errno_location", __errno_location ); - writejump( "__h_errno_location", __h_errno_location ); - writejump( "__res_state", __res_state ); - } - descr->cancel_state = PTHREAD_CANCEL_ENABLE; - descr->cancel_type = PTHREAD_CANCEL_ASYNCHRONOUS; - if (libc_uselocale) libc_uselocale( -1 /*LC_GLOBAL_LOCALE*/ ); -} - - -/*********************************************************************** - * create_thread - */ -static int create_thread( struct wine_pthread_thread_info *info ) -{ - if (!info->stack_base) - { - info->stack_base = wine_anon_mmap( NULL, info->stack_size, PROT_READ | PROT_WRITE, 0 ); - if (info->stack_base == (void *)-1) return -1; - } -#ifdef HAVE_CLONE - if (clone( (int (*)(void *))info->entry, (char *)info->stack_base + info->stack_size, - CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, info ) < 0) - return -1; - return 0; -#elif defined(HAVE_RFORK) - { - void **sp = (void **)((char *)info->stack_base + info->stack_size); - *--sp = info; - *--sp = 0; - *--sp = info->entry; - __asm__ __volatile__( - "pushl %2;\n\t" /* flags */ - "pushl $0;\n\t" /* 0 ? */ - "movl %1,%%eax;\n\t" /* SYS_rfork */ - ".byte 0x9a; .long 0; .word 7;\n\t" /* lcall 7:0... FreeBSD syscall */ - "cmpl $0, %%edx;\n\t" - "je 1f;\n\t" - "movl %0,%%esp;\n\t" /* child -> new thread */ - "ret;\n" - "1:\n\t" /* parent -> caller thread */ - "addl $8,%%esp" : - : "r" (sp), "r" (SYS_rfork), "r" (RFPROC | RFMEM | RFTHREAD) - : "eax", "edx"); - return 0; - } -#endif - return -1; -} - - -/*********************************************************************** - * init_current_teb - * - * Set the current TEB for a new thread. - */ -static void init_current_teb( struct wine_pthread_thread_info *info ) -{ - /* On the i386, the current thread is in the %fs register */ - LDT_ENTRY fs_entry; - - wine_ldt_set_base( &fs_entry, info->teb_base ); - wine_ldt_set_limit( &fs_entry, info->teb_size - 1 ); - wine_ldt_set_flags( &fs_entry, WINE_LDT_FLAGS_DATA|WINE_LDT_FLAGS_32BIT ); - wine_ldt_init_fs( info->teb_sel, &fs_entry ); - - /* set pid and tid */ - info->pid = getpid(); - info->tid = -1; -} - - -/*********************************************************************** - * get_current_teb - */ -static void *get_current_teb(void) -{ - void *ret; - __asm__( ".byte 0x64\n\tmovl 0x18,%0" : "=r" (ret) ); - return ret; -} - - -/*********************************************************************** - * exit_thread - */ -static void DECLSPEC_NORETURN exit_thread( struct wine_pthread_thread_info *info ) -{ - wine_switch_to_stack( cleanup_thread, info, get_temp_stack() ); -} - - -/*********************************************************************** - * abort_thread - */ -static void DECLSPEC_NORETURN abort_thread( long status ) -{ - _exit( status ); -} - - -/*********************************************************************** - * pthread_functions - */ -static const struct wine_pthread_functions pthread_functions = -{ - init_process, - init_thread, - create_thread, - init_current_teb, - get_current_teb, - exit_thread, - abort_thread, - sigprocmask -}; - -void init_pthread_functions(void) -{ - wine_pthread_set_functions( &pthread_functions, sizeof(pthread_functions) ); -} - -/* Currently this probably works only for glibc2, - * which checks for the presence of double-underscore-prepended - * pthread primitives, and use them if available. - * If they are not available, the libc defaults to - * non-threadsafe operation (not good). */ - -#if defined(HAVE_PTHREAD_H) && (defined(__GLIBC__) || defined(__FreeBSD__)) - -/* adapt as necessary (a construct like this is used in glibc sources) */ -#define strong_alias(orig, alias) \ - asm(".globl " PSTR(alias) "\n" \ - "\t.set " PSTR(alias) "," PSTR(orig)) - -struct fork_block; - -/* pthread functions redirection */ - -struct pthread_functions -{ - pid_t (*ptr_pthread_fork) (struct fork_block *); - int (*ptr_pthread_attr_destroy) (pthread_attr_t *); - int (*ptr___pthread_attr_init_2_0) (pthread_attr_t *); - int (*ptr___pthread_attr_init_2_1) (pthread_attr_t *); - int (*ptr_pthread_attr_getdetachstate) (const pthread_attr_t *, int *); - int (*ptr_pthread_attr_setdetachstate) (pthread_attr_t *, int); - int (*ptr_pthread_attr_getinheritsched) (const pthread_attr_t *, int *); - int (*ptr_pthread_attr_setinheritsched) (pthread_attr_t *, int); - int (*ptr_pthread_attr_getschedparam) (const pthread_attr_t *, struct sched_param *); - int (*ptr_pthread_attr_setschedparam) (pthread_attr_t *, const struct sched_param *); - int (*ptr_pthread_attr_getschedpolicy) (const pthread_attr_t *, int *); - int (*ptr_pthread_attr_setschedpolicy) (pthread_attr_t *, int); - int (*ptr_pthread_attr_getscope) (const pthread_attr_t *, int *); - int (*ptr_pthread_attr_setscope) (pthread_attr_t *, int); - int (*ptr_pthread_condattr_destroy) (pthread_condattr_t *); - int (*ptr_pthread_condattr_init) (pthread_condattr_t *); - int (*ptr___pthread_cond_broadcast) (pthread_cond_t *); - int (*ptr___pthread_cond_destroy) (pthread_cond_t *); - int (*ptr___pthread_cond_init) (pthread_cond_t *, const pthread_condattr_t *); - int (*ptr___pthread_cond_signal) (pthread_cond_t *); - int (*ptr___pthread_cond_wait) (pthread_cond_t *, pthread_mutex_t *); - int (*ptr_pthread_equal) (pthread_t, pthread_t); - void (*ptr___pthread_exit) (void *); - int (*ptr_pthread_getschedparam) (pthread_t, int *, struct sched_param *); - int (*ptr_pthread_setschedparam) (pthread_t, int, const struct sched_param *); - int (*ptr_pthread_mutex_destroy) (pthread_mutex_t *); - int (*ptr_pthread_mutex_init) (pthread_mutex_t *, const pthread_mutexattr_t *); - int (*ptr_pthread_mutex_lock) (pthread_mutex_t *); - int (*ptr_pthread_mutex_trylock) (pthread_mutex_t *); - int (*ptr_pthread_mutex_unlock) (pthread_mutex_t *); - pthread_t (*ptr_pthread_self) (void); - int (*ptr_pthread_setcancelstate) (int, int *); - int (*ptr_pthread_setcanceltype) (int, int *); - void (*ptr_pthread_do_exit) (void *retval, char *currentframe); - void (*ptr_pthread_cleanup_upto) (jmp_buf target, char *targetframe); - pthread_descr (*ptr_pthread_thread_self) (void); - int (*ptr_pthread_internal_tsd_set) (int key, const void *pointer); - void * (*ptr_pthread_internal_tsd_get) (int key); - void ** __attribute__ ((__const__)) (*ptr_pthread_internal_tsd_address) (int key); - int (*ptr_pthread_sigaction) (int sig, const struct sigaction * act, struct sigaction *oact); - int (*ptr_pthread_sigwait) (const sigset_t *set, int *sig); - int (*ptr_pthread_raise) (int sig); - int (*ptr___pthread_cond_timedwait) (pthread_cond_t *, pthread_mutex_t *, const struct timespec *); - void (*ptr__pthread_cleanup_push) (struct _pthread_cleanup_buffer * buffer, void (*routine)(void *), void * arg); - void (*ptr__pthread_cleanup_pop) (struct _pthread_cleanup_buffer * buffer, int execute); -}; - -static pid_t (*libc_fork)(void); -static int (*libc_sigaction)(int signum, const struct sigaction *act, struct sigaction *oldact); -static int *(*libc_pthread_init)( const struct pthread_functions *funcs ); - -static struct pthread_functions libc_pthread_functions; - -strong_alias(__pthread_thread_self, pthread_thread_self); - -/* redefine this to prevent libpthread from overriding our function pointers */ -int *__libc_pthread_init( const struct pthread_functions *funcs ) -{ - return libc_multiple_threads; -} - -typedef struct _wine_cleanup { - void (*routine)(void *); - void *arg; -} *wine_cleanup; - -int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* - (*start_routine)(void *), void* arg) -{ - assert( funcs.ptr_pthread_create ); - return funcs.ptr_pthread_create( thread, attr, start_routine, arg ); -} - -int pthread_cancel(pthread_t thread) -{ - assert( funcs.ptr_pthread_cancel ); - return funcs.ptr_pthread_cancel( thread ); -} - -int pthread_join(pthread_t thread, void **value_ptr) -{ - assert( funcs.ptr_pthread_join ); - return funcs.ptr_pthread_join( thread, value_ptr ); -} - -int pthread_detach(pthread_t thread) -{ - assert( funcs.ptr_pthread_detach ); - return funcs.ptr_pthread_detach( thread ); -} - -/* FIXME: we have no equivalents in win32 for the policys */ -/* so just keep this as a stub */ -int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) -{ - P_OUTPUT("FIXME:pthread_attr_setschedpolicy\n"); - return 0; -} - -/* FIXME: no win32 equivalent for scope */ -int pthread_attr_setscope(pthread_attr_t *attr, int scope) -{ - P_OUTPUT("FIXME:pthread_attr_setscope\n"); - return 0; /* return success */ -} - -/* FIXME: no win32 equivalent for schedule param */ -int pthread_attr_setschedparam(pthread_attr_t *attr, - const struct sched_param *param) -{ - P_OUTPUT("FIXME:pthread_attr_setschedparam\n"); - return 0; /* return success */ -} - -/* FIXME */ -int pthread_attr_setstack(pthread_attr_t *attr, void *addr, size_t size) -{ - return 0; /* return success */ -} - -int __pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) -{ - static pthread_once_t the_once = PTHREAD_ONCE_INIT; - int once_now; - - memcpy(&once_now,&the_once,sizeof(once_now)); - if (interlocked_cmpxchg((int*)once_control, once_now+1, once_now) == once_now) - (*init_routine)(); - return 0; -} -strong_alias(__pthread_once, pthread_once); - -void __pthread_kill_other_threads_np(void) -{ - /* we don't need to do anything here */ -} -strong_alias(__pthread_kill_other_threads_np, pthread_kill_other_threads_np); - -/***** atfork *****/ - -#define MAX_ATFORK 8 /* libc doesn't need that many anyway */ - -static pthread_mutex_t atfork_mutex = PTHREAD_MUTEX_INITIALIZER; - -typedef void (*atfork_handler)(void); -static atfork_handler atfork_prepare[MAX_ATFORK]; -static atfork_handler atfork_parent[MAX_ATFORK]; -static atfork_handler atfork_child[MAX_ATFORK]; -static int atfork_count; - -int __pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) -{ - pthread_mutex_lock( &atfork_mutex ); - assert( atfork_count < MAX_ATFORK ); - atfork_prepare[atfork_count] = prepare; - atfork_parent[atfork_count] = parent; - atfork_child[atfork_count] = child; - atfork_count++; - pthread_mutex_unlock( &atfork_mutex ); - return 0; -} -strong_alias(__pthread_atfork, pthread_atfork); - -pid_t __fork(void) -{ - pid_t pid; - int i; - - if (!libc_fork) - { - libc_fork = wine_dlsym( RTLD_NEXT, "fork", NULL, 0 ); - assert( libc_fork ); - } - pthread_mutex_lock( &atfork_mutex ); - /* prepare handlers are called in reverse insertion order */ - for (i = atfork_count - 1; i >= 0; i--) if (atfork_prepare[i]) atfork_prepare[i](); - if (!(pid = libc_fork())) - { - pthread_mutex_init( &atfork_mutex, NULL ); - for (i = 0; i < atfork_count; i++) if (atfork_child[i]) atfork_child[i](); - } - else - { - for (i = 0; i < atfork_count; i++) if (atfork_parent[i]) atfork_parent[i](); - pthread_mutex_unlock( &atfork_mutex ); - } - return pid; -} -strong_alias(__fork, fork); - -/***** MUTEXES *****/ - -int __pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr) -{ - if (!funcs.ptr_pthread_mutex_init) return 0; - return funcs.ptr_pthread_mutex_init( mutex, mutexattr ); -} -strong_alias(__pthread_mutex_init, pthread_mutex_init); - -int __pthread_mutex_lock(pthread_mutex_t *mutex) -{ - if (!funcs.ptr_pthread_mutex_lock) return 0; - return funcs.ptr_pthread_mutex_lock( mutex ); -} -strong_alias(__pthread_mutex_lock, pthread_mutex_lock); - -int __pthread_mutex_trylock(pthread_mutex_t *mutex) -{ - if (!funcs.ptr_pthread_mutex_trylock) return 0; - return funcs.ptr_pthread_mutex_trylock( mutex ); -} -strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock); - -int __pthread_mutex_unlock(pthread_mutex_t *mutex) -{ - if (!funcs.ptr_pthread_mutex_unlock) return 0; - return funcs.ptr_pthread_mutex_unlock( mutex ); -} -strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock); - -int __pthread_mutex_destroy(pthread_mutex_t *mutex) -{ - if (!funcs.ptr_pthread_mutex_destroy) return 0; - return funcs.ptr_pthread_mutex_destroy( mutex ); -} -strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy); - - -/***** MUTEX ATTRIBUTES *****/ -/* just dummies, since critical sections are always recursive */ - -int __pthread_mutexattr_init(pthread_mutexattr_t *attr) -{ - return 0; -} -strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init); - -int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr) -{ - return 0; -} -strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy); - -int __pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind) -{ - return 0; -} -strong_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np); - -int __pthread_mutexattr_getkind_np(pthread_mutexattr_t *attr, int *kind) -{ - *kind = PTHREAD_MUTEX_RECURSIVE; - return 0; -} -strong_alias(__pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np); - -int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind) -{ - return 0; -} -strong_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype); - -int __pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *kind) -{ - *kind = PTHREAD_MUTEX_RECURSIVE; - return 0; -} -strong_alias(__pthread_mutexattr_gettype, pthread_mutexattr_gettype); - - -/***** THREAD-SPECIFIC VARIABLES (KEYS) *****/ - -int __pthread_key_create(pthread_key_t *key, void (*destr_function)(void *)) -{ - static int keycnt = FIRST_KEY; - *key = interlocked_xchg_add(&keycnt, 1); - return 0; -} -strong_alias(__pthread_key_create, pthread_key_create); - -int __pthread_key_delete(pthread_key_t key) -{ - return 0; -} -strong_alias(__pthread_key_delete, pthread_key_delete); - -int __pthread_setspecific(pthread_key_t key, const void *pointer) -{ - pthread_descr descr = __pthread_thread_self(); - descr->key_data[key] = pointer; - return 0; -} -strong_alias(__pthread_setspecific, pthread_setspecific); - -void *__pthread_getspecific(pthread_key_t key) -{ - pthread_descr descr = __pthread_thread_self(); - return (void *)descr->key_data[key]; -} -strong_alias(__pthread_getspecific, pthread_getspecific); - -static int pthread_internal_tsd_set( int key, const void *pointer ) -{ - pthread_descr descr = __pthread_thread_self(); - descr->tsd_data[key] = pointer; - return 0; -} -int (*__libc_internal_tsd_set)(int, const void *) = pthread_internal_tsd_set; - -static void *pthread_internal_tsd_get( int key ) -{ - pthread_descr descr = __pthread_thread_self(); - return (void *)descr->tsd_data[key]; -} -void* (*__libc_internal_tsd_get)(int) = pthread_internal_tsd_get; - -static void ** __attribute__((const)) pthread_internal_tsd_address( int key ) -{ - pthread_descr descr = __pthread_thread_self(); - return (void **)&descr->tsd_data[key]; -} -void** (*__libc_internal_tsd_address)(int) = pthread_internal_tsd_address; - -/***** "EXCEPTION" FRAMES *****/ -/* not implemented right now */ - -void _pthread_cleanup_push(struct _pthread_cleanup_buffer *buffer, void (*routine)(void *), void *arg) -{ - ((wine_cleanup)buffer)->routine = routine; - ((wine_cleanup)buffer)->arg = arg; -} - -void _pthread_cleanup_pop(struct _pthread_cleanup_buffer *buffer, int execute) -{ - if (execute) (*(((wine_cleanup)buffer)->routine))(((wine_cleanup)buffer)->arg); -} - -void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer *buffer, void (*routine)(void *), void *arg) -{ - _pthread_cleanup_push(buffer, routine, arg); -} - -void _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer *buffer, int execute) -{ - _pthread_cleanup_pop(buffer, execute); -} - -void __pthread_cleanup_upto(jmp_buf target, char *frame) -{ - /* FIXME */ -} - -/***** CONDITIONS *****/ - -int __pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) -{ - if (!funcs.ptr_pthread_cond_init) return 0; - return funcs.ptr_pthread_cond_init(cond, cond_attr); -} -strong_alias(__pthread_cond_init, pthread_cond_init); - -int __pthread_cond_destroy(pthread_cond_t *cond) -{ - if (!funcs.ptr_pthread_cond_destroy) return 0; - return funcs.ptr_pthread_cond_destroy(cond); -} -strong_alias(__pthread_cond_destroy, pthread_cond_destroy); - -int __pthread_cond_signal(pthread_cond_t *cond) -{ - if (!funcs.ptr_pthread_cond_signal) return 0; - return funcs.ptr_pthread_cond_signal(cond); -} -strong_alias(__pthread_cond_signal, pthread_cond_signal); - -int __pthread_cond_broadcast(pthread_cond_t *cond) -{ - if (!funcs.ptr_pthread_cond_broadcast) return 0; - return funcs.ptr_pthread_cond_broadcast(cond); -} -strong_alias(__pthread_cond_broadcast, pthread_cond_broadcast); - -int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) -{ - if (!funcs.ptr_pthread_cond_wait) return 0; - return funcs.ptr_pthread_cond_wait(cond, mutex); -} -strong_alias(__pthread_cond_wait, pthread_cond_wait); - -int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) -{ - if (!funcs.ptr_pthread_cond_timedwait) return 0; - return funcs.ptr_pthread_cond_timedwait(cond, mutex, abstime); -} -strong_alias(__pthread_cond_timedwait, pthread_cond_timedwait); - -/**** CONDITION ATTRIBUTES *****/ -/* not implemented right now */ - -int pthread_condattr_init(pthread_condattr_t *attr) -{ - return 0; -} - -int pthread_condattr_destroy(pthread_condattr_t *attr) -{ - return 0; -} - -/***** READ-WRITE LOCKS *****/ - -int __pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *rwlock_attr) -{ - assert( funcs.ptr_pthread_rwlock_init ); - return funcs.ptr_pthread_rwlock_init( rwlock, rwlock_attr ); -} -strong_alias(__pthread_rwlock_init, pthread_rwlock_init); - -int __pthread_rwlock_destroy(pthread_rwlock_t *rwlock) -{ - assert( funcs.ptr_pthread_rwlock_destroy ); - return funcs.ptr_pthread_rwlock_destroy( rwlock ); -} -strong_alias(__pthread_rwlock_destroy, pthread_rwlock_destroy); - -int __pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) -{ - if (!funcs.ptr_pthread_rwlock_rdlock) return 0; - return funcs.ptr_pthread_rwlock_rdlock( rwlock ); -} -strong_alias(__pthread_rwlock_rdlock, pthread_rwlock_rdlock); - -int __pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) -{ - assert( funcs.ptr_pthread_rwlock_tryrdlock ); - return funcs.ptr_pthread_rwlock_tryrdlock( rwlock ); -} -strong_alias(__pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock); - -int __pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) -{ - assert( funcs.ptr_pthread_rwlock_wrlock ); - return funcs.ptr_pthread_rwlock_wrlock( rwlock ); -} -strong_alias(__pthread_rwlock_wrlock, pthread_rwlock_wrlock); - -int __pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) -{ - assert( funcs.ptr_pthread_rwlock_trywrlock ); - return funcs.ptr_pthread_rwlock_trywrlock( rwlock ); -} -strong_alias(__pthread_rwlock_trywrlock, pthread_rwlock_trywrlock); - -int __pthread_rwlock_unlock(pthread_rwlock_t *rwlock) -{ - if (!funcs.ptr_pthread_rwlock_unlock) return 0; - return funcs.ptr_pthread_rwlock_unlock( rwlock ); -} -strong_alias(__pthread_rwlock_unlock, pthread_rwlock_unlock); - -/**** READ-WRITE LOCK ATTRIBUTES *****/ -/* not implemented right now */ - -int pthread_rwlockattr_init(pthread_rwlockattr_t *attr) -{ - return 0; -} - -int __pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr) -{ - return 0; -} -strong_alias(__pthread_rwlockattr_destroy, pthread_rwlockattr_destroy); - -int pthread_rwlockattr_getkind_np(const pthread_rwlockattr_t *attr, int *pref) -{ - *pref = 0; - return 0; -} - -int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *attr, int pref) -{ - return 0; -} - -/***** MISC *****/ - -pthread_t pthread_self(void) -{ - assert( funcs.ptr_pthread_self ); - return funcs.ptr_pthread_self(); -} - -int pthread_equal(pthread_t thread1, pthread_t thread2) -{ - assert( funcs.ptr_pthread_equal ); - return funcs.ptr_pthread_equal( thread1, thread2 ); -} - -void __pthread_do_exit(void *retval, char *currentframe) -{ - assert( funcs.ptr_pthread_exit ); - return funcs.ptr_pthread_exit( retval, currentframe ); -} - -void __pthread_exit(void *retval) -{ - __pthread_do_exit( retval, NULL ); -} -strong_alias(__pthread_exit, pthread_exit); - -int pthread_setcancelstate(int state, int *oldstate) -{ - pthread_descr descr = __pthread_thread_self(); - if (oldstate) *oldstate = descr->cancel_state; - descr->cancel_state = state; - return 0; -} - -int pthread_setcanceltype(int type, int *oldtype) -{ - pthread_descr descr = __pthread_thread_self(); - if (oldtype) *oldtype = descr->cancel_type; - descr->cancel_type = type; - return 0; -} - -/***** ANTI-OVERRIDES *****/ -/* pthreads tries to override these, point them back to libc */ - -int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) -{ - if (!libc_sigaction) - { - libc_sigaction = wine_dlsym( RTLD_NEXT, "sigaction", NULL, 0 ); - assert( libc_sigaction ); - } - return libc_sigaction(signum, act, oldact); -} - -void __pthread_initialize(void) -{ - static int done; - - if (!done) - { - done = 1; - libc_fork = wine_dlsym( RTLD_NEXT, "fork", NULL, 0 ); - libc_sigaction = wine_dlsym( RTLD_NEXT, "sigaction", NULL, 0 ); - libc_uselocale = wine_dlsym( RTLD_DEFAULT, "uselocale", NULL, 0 ); - libc_pthread_init = wine_dlsym( RTLD_NEXT, "__libc_pthread_init", NULL, 0 ); - if (libc_pthread_init) libc_multiple_threads = libc_pthread_init( &libc_pthread_functions ); - } -} - -#ifdef __GNUC__ -static void init(void) __attribute__((constructor)); -static void init(void) -{ - __pthread_initialize(); -} -#endif - -static struct pthread_functions libc_pthread_functions = -{ - NULL, /* ptr_pthread_fork */ - NULL, /* FIXME */ /* ptr_pthread_attr_destroy */ - NULL, /* FIXME */ /* ptr___pthread_attr_init_2_0 */ - NULL, /* FIXME */ /* ptr___pthread_attr_init_2_1 */ - NULL, /* FIXME */ /* ptr_pthread_attr_getdetachstate */ - NULL, /* FIXME */ /* ptr_pthread_attr_setdetachstate */ - NULL, /* FIXME */ /* ptr_pthread_attr_getinheritsched */ - NULL, /* FIXME */ /* ptr_pthread_attr_setinheritsched */ - NULL, /* FIXME */ /* ptr_pthread_attr_getschedparam */ - pthread_attr_setschedparam, /* ptr_pthread_attr_setschedparam */ - NULL, /* FIXME */ /* ptr_pthread_attr_getschedpolicy */ - NULL, /* FIXME */ /* ptr_pthread_attr_setschedpolicy */ - NULL, /* FIXME */ /* ptr_pthread_attr_getscope */ - NULL, /* FIXME */ /* ptr_pthread_attr_setscope */ - pthread_condattr_destroy, /* ptr_pthread_condattr_destroy */ - pthread_condattr_init, /* ptr_pthread_condattr_init */ - __pthread_cond_broadcast, /* ptr___pthread_cond_broadcast */ - __pthread_cond_destroy, /* ptr___pthread_cond_destroy */ - __pthread_cond_init, /* ptr___pthread_cond_init */ - __pthread_cond_signal, /* ptr___pthread_cond_signal */ - __pthread_cond_wait, /* ptr___pthread_cond_wait */ - pthread_equal, /* ptr_pthread_equal */ - __pthread_exit, /* ptr___pthread_exit */ - NULL, /* FIXME */ /* ptr_pthread_getschedparam */ - NULL, /* FIXME */ /* ptr_pthread_setschedparam */ - __pthread_mutex_destroy, /* ptr_pthread_mutex_destroy */ - __pthread_mutex_init, /* ptr_pthread_mutex_init */ - __pthread_mutex_lock, /* ptr_pthread_mutex_lock */ - __pthread_mutex_trylock, /* ptr_pthread_mutex_trylock */ - __pthread_mutex_unlock, /* ptr_pthread_mutex_unlock */ - pthread_self, /* ptr_pthread_self */ - pthread_setcancelstate, /* ptr_pthread_setcancelstate */ - pthread_setcanceltype, /* ptr_pthread_setcanceltype */ - __pthread_do_exit, /* ptr_pthread_do_exit */ - __pthread_cleanup_upto, /* ptr_pthread_cleanup_upto */ - __pthread_thread_self, /* ptr_pthread_thread_self */ - pthread_internal_tsd_set, /* ptr_pthread_internal_tsd_set */ - pthread_internal_tsd_get, /* ptr_pthread_internal_tsd_get */ - pthread_internal_tsd_address, /* ptr_pthread_internal_tsd_address */ - NULL, /* ptr_pthread_sigaction */ - NULL, /* ptr_pthread_sigwait */ - NULL, /* ptr_pthread_raise */ - __pthread_cond_timedwait, /* ptr___pthread_cond_timedwait */ - _pthread_cleanup_push, /* ptr__pthread_cleanup_push */ - _pthread_cleanup_pop /* ptr__pthread_cleanup_pop */ -}; - -#endif /* HAVE_PTHREAD_H && (__GLIBC__ || __FREEBSD__) */