From c4567214356c61e7d5fd2d1635df91caed681030 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 26 Mar 2009 13:20:04 +0100 Subject: [PATCH] ntdll: Get rid of the no longer used pthread emulation. --- dlls/ntdll/Makefile.in | 1 - dlls/ntdll/ntdll_misc.h | 1 - dlls/ntdll/pthread.c | 599 ---------------------------------------- dlls/ntdll/thread.c | 1 - 4 files changed, 602 deletions(-) delete mode 100644 dlls/ntdll/pthread.c diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in index 98fe9217601..a37204438ea 100644 --- a/dlls/ntdll/Makefile.in +++ b/dlls/ntdll/Makefile.in @@ -31,7 +31,6 @@ C_SRCS = \ path.c \ printf.c \ process.c \ - pthread.c \ reg.c \ relay.c \ resource.c \ diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index fa99b3164b8..56e2b2fd645 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -62,7 +62,6 @@ extern size_t get_signal_stack_total_size(void); extern void version_init( const WCHAR *appname ); extern void debug_init(void); extern HANDLE thread_init(void); -extern void pthread_init(void); extern void actctx_init(void); extern void virtual_init(void); extern void virtual_init_threading(void); diff --git a/dlls/ntdll/pthread.c b/dlls/ntdll/pthread.c deleted file mode 100644 index 60b6033c3f3..00000000000 --- a/dlls/ntdll/pthread.c +++ /dev/null @@ -1,599 +0,0 @@ -/* - * pthread emulation for re-entrant libcs - * - * 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" - -#ifdef HAVE_PTHREAD_H - -#define _GNU_SOURCE /* we may need to override some GNU extensions */ - -#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 - -#include "windef.h" -#include "winbase.h" -#include "winternl.h" -#include "ntdll_misc.h" -#include "wine/pthread.h" - -#define P_OUTPUT(stuff) write(2,stuff,strlen(stuff)) - -/* NOTE: This is a truly extremely incredibly ugly hack! - * But it does seem to work... */ - -/* assume that pthread_mutex_t has room for at least one pointer, - * and hope that the users of pthread_mutex_t considers it opaque - * (never checks what's in it) - * also: assume that static initializer sets pointer to NULL - */ -typedef struct -{ -#ifdef __GLIBC__ - int reserved; -#endif - CRITICAL_SECTION *critsect; -} *wine_mutex; - -/* see wine_mutex above for comments */ -typedef struct { - RTL_RWLOCK *lock; -} *wine_rwlock; - -struct pthread_thread_init -{ - void* (*start_routine)(void*); - void* arg; -}; - -static void wine_pthread_exit(void *retval, char *currentframe) -{ - RtlFreeThreadActivationContextStack(); - RtlExitUserThread( PtrToUlong(retval) ); -} - -static void CALLBACK pthread_thread_start(LPVOID data) -{ - struct pthread_thread_init init = *(struct pthread_thread_init*)data; - RtlFreeHeap(GetProcessHeap(),0,data); - wine_pthread_exit( init.start_routine(init.arg), NULL ); -} - -static int wine_pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* - (*start_routine)(void *), void* arg) -{ - HANDLE handle; - CLIENT_ID client_id; - struct pthread_thread_init* idata; - - if (!(idata = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*idata)))) return ENOMEM; - - idata->start_routine = start_routine; - idata->arg = arg; - if (!RtlCreateUserThread( NtCurrentProcess(), NULL, FALSE, NULL, 0, 0, - pthread_thread_start, idata, &handle, &client_id )) - { - NtClose( handle ); - *thread = (pthread_t)client_id.UniqueThread; - } - else - { - RtlFreeHeap( GetProcessHeap(), 0, idata ); - return EAGAIN; - } - - return 0; -} - -static int wine_pthread_cancel(pthread_t thread) -{ - CLIENT_ID cid; - NTSTATUS status; - HANDLE handle; - - cid.UniqueProcess = 0; - cid.UniqueThread = (HANDLE)thread; - status = NtOpenThread( &handle, THREAD_TERMINATE, NULL, &cid ); - if (!status) - { - status = NtTerminateThread( handle, 0 ); - NtClose( handle ); - } - if (status) return EINVAL; - return 0; -} - -static int wine_pthread_join(pthread_t thread, void **value_ptr) -{ - THREAD_BASIC_INFORMATION info; - CLIENT_ID cid; - NTSTATUS status; - HANDLE handle; - - cid.UniqueProcess = 0; - cid.UniqueThread = (HANDLE)thread; - status = NtOpenThread( &handle, THREAD_QUERY_INFORMATION|SYNCHRONIZE, NULL, &cid ); - if (!status) - { - NtWaitForMultipleObjects( 1, &handle, FALSE, FALSE, NULL ); - status = NtQueryInformationThread( handle, ThreadBasicInformation, &info, sizeof(info), NULL ); - NtClose( handle ); - if (!status) *value_ptr = UlongToPtr(info.ExitStatus); - } - if (status) return EINVAL; /* FIXME: make this more correctly match windows errors */ - return 0; -} - -/*FIXME: not sure what to do with this one... */ -static int wine_pthread_detach(pthread_t thread) -{ - P_OUTPUT("FIXME:pthread_detach\n"); - return 0; -} - -/***** MUTEXES *****/ - -static int wine_pthread_mutex_init(pthread_mutex_t *mutex, - const pthread_mutexattr_t *mutexattr) -{ - /* glibc has a tendency to initialize mutexes very often, even - in situations where they are not really used later on. - - As for us, initializing a mutex is very expensive, we postpone - the real initialization until the time the mutex is first used. */ - - ((wine_mutex)mutex)->critsect = NULL; - return 0; -} - -static void mutex_real_init( pthread_mutex_t *mutex ) -{ - CRITICAL_SECTION *critsect = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(CRITICAL_SECTION)); - RtlInitializeCriticalSection(critsect); - - if (interlocked_cmpxchg_ptr((void**)&(((wine_mutex)mutex)->critsect),critsect,NULL) != NULL) { - /* too late, some other thread already did it */ - RtlDeleteCriticalSection(critsect); - RtlFreeHeap(GetProcessHeap(), 0, critsect); - } -} - -static int wine_pthread_mutex_lock(pthread_mutex_t *mutex) -{ - if (!((wine_mutex)mutex)->critsect) - mutex_real_init( mutex ); - - RtlEnterCriticalSection(((wine_mutex)mutex)->critsect); - return 0; -} - -static int wine_pthread_mutex_trylock(pthread_mutex_t *mutex) -{ - if (!((wine_mutex)mutex)->critsect) - mutex_real_init( mutex ); - - if (!RtlTryEnterCriticalSection(((wine_mutex)mutex)->critsect)) return EBUSY; - return 0; -} - -static int wine_pthread_mutex_unlock(pthread_mutex_t *mutex) -{ - CRITICAL_SECTION *crit = ((wine_mutex)mutex)->critsect; - - if (!crit) return 0; - if (crit->OwningThread != ULongToHandle(GetCurrentThreadId())) return EPERM; - RtlLeaveCriticalSection( crit ); - return 0; -} - -static int wine_pthread_mutex_destroy(pthread_mutex_t *mutex) -{ - if (!((wine_mutex)mutex)->critsect) return 0; - if (((wine_mutex)mutex)->critsect->RecursionCount) { -#if 0 /* there seems to be a bug in libc6 that makes this a bad idea */ - return EBUSY; -#else - while (((wine_mutex)mutex)->critsect->RecursionCount) - RtlLeaveCriticalSection(((wine_mutex)mutex)->critsect); -#endif - } - RtlDeleteCriticalSection(((wine_mutex)mutex)->critsect); - RtlFreeHeap(GetProcessHeap(), 0, ((wine_mutex)mutex)->critsect); - ((wine_mutex)mutex)->critsect = NULL; - return 0; -} - -/***** READ-WRITE LOCKS *****/ - -static void rwlock_real_init(pthread_rwlock_t *rwlock) -{ - RTL_RWLOCK *lock = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_RWLOCK)); - RtlInitializeResource(lock); - - if (interlocked_cmpxchg_ptr((void**)&(((wine_rwlock)rwlock)->lock),lock,NULL) != NULL) { - /* too late, some other thread already did it */ - RtlDeleteResource(lock); - RtlFreeHeap(GetProcessHeap(), 0, lock); - } -} - -static int wine_pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *rwlock_attr) -{ - ((wine_rwlock)rwlock)->lock = NULL; - return 0; -} - -static int wine_pthread_rwlock_destroy(pthread_rwlock_t *rwlock) -{ - if (!((wine_rwlock)rwlock)->lock) return 0; - RtlDeleteResource(((wine_rwlock)rwlock)->lock); - RtlFreeHeap(GetProcessHeap(), 0, ((wine_rwlock)rwlock)->lock); - return 0; -} - -static int wine_pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) -{ - if (!((wine_rwlock)rwlock)->lock) - rwlock_real_init( rwlock ); - - while(TRUE) - if (RtlAcquireResourceShared(((wine_rwlock)rwlock)->lock, TRUE)) - return 0; -} - -static int wine_pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) -{ - if (!((wine_rwlock)rwlock)->lock) - rwlock_real_init( rwlock ); - - if (!RtlAcquireResourceShared(((wine_rwlock)rwlock)->lock, FALSE)) return EBUSY; - return 0; -} - -static int wine_pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) -{ - if (!((wine_rwlock)rwlock)->lock) - rwlock_real_init( rwlock ); - - while(TRUE) - if (RtlAcquireResourceExclusive(((wine_rwlock)rwlock)->lock, TRUE)) - return 0; -} - -static int wine_pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) -{ - if (!((wine_rwlock)rwlock)->lock) - rwlock_real_init( rwlock ); - - if (!RtlAcquireResourceExclusive(((wine_rwlock)rwlock)->lock, FALSE)) return EBUSY; - return 0; -} - -static int wine_pthread_rwlock_unlock(pthread_rwlock_t *rwlock) -{ - if (!((wine_rwlock)rwlock)->lock) return 0; - RtlReleaseResource( ((wine_rwlock)rwlock)->lock ); - return 0; -} - -/***** CONDITIONS *****/ - -/* The condition code is basically cut-and-pasted from Douglas - * Schmidt's paper: - * "Strategies for Implementing POSIX Condition Variables on Win32", - * at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html and - * http://www.cs.wustl.edu/~schmidt/win32-cv-2.html. - * This paper formed the basis for the condition variable - * implementation used in the ACE library. - */ - -/* Possible problems with ACE: - * - unimplemented pthread_mutexattr_init - */ -typedef struct { - /* Number of waiting threads. */ - int waiters_count; - - /* Serialize access to . */ - CRITICAL_SECTION waiters_count_lock; - - /* - * Semaphore used to queue up threads waiting for the condition to - * become signaled. - */ - HANDLE sema; - - /* - * An auto-reset event used by the broadcast/signal thread to wait - * for all the waiting thread(s) to wake up and be released from the - * semaphore. - */ - HANDLE waiters_done; - - /* - * Keeps track of whether we were broadcasting or signaling. This - * allows us to optimize the code if we're just signaling. - */ - size_t was_broadcast; -} wine_cond_detail; - -/* see wine_mutex above for comments */ -typedef struct { - wine_cond_detail *cond; -} *wine_cond; - -static void wine_cond_real_init(pthread_cond_t *cond) -{ - wine_cond_detail *detail = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(wine_cond_detail)); - detail->waiters_count = 0; - detail->was_broadcast = 0; - NtCreateSemaphore( &detail->sema, SEMAPHORE_ALL_ACCESS, NULL, 0, 0x7fffffff ); - NtCreateEvent( &detail->waiters_done, EVENT_ALL_ACCESS, NULL, FALSE, FALSE ); - RtlInitializeCriticalSection (&detail->waiters_count_lock); - - if (interlocked_cmpxchg_ptr((void**)&(((wine_cond)cond)->cond), detail, NULL) != NULL) - { - /* too late, some other thread already did it */ - P_OUTPUT("FIXME:pthread_cond_init:expect troubles...\n"); - NtClose(detail->sema); - RtlDeleteCriticalSection(&detail->waiters_count_lock); - NtClose(detail->waiters_done); - RtlFreeHeap(GetProcessHeap(), 0, detail); - } -} - -static int wine_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) -{ - /* The same as for wine_pthread_mutex_init, we postpone initialization - until condition is really used.*/ - ((wine_cond)cond)->cond = NULL; - return 0; -} - -static int wine_pthread_cond_destroy(pthread_cond_t *cond) -{ - wine_cond_detail *detail = ((wine_cond)cond)->cond; - - if (!detail) return 0; - NtClose(detail->sema); - RtlDeleteCriticalSection(&detail->waiters_count_lock); - NtClose(detail->waiters_done); - RtlFreeHeap(GetProcessHeap(), 0, detail); - ((wine_cond)cond)->cond = NULL; - return 0; -} - -static int wine_pthread_cond_signal(pthread_cond_t *cond) -{ - int have_waiters; - wine_cond_detail *detail; - - if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond); - detail = ((wine_cond)cond)->cond; - - RtlEnterCriticalSection (&detail->waiters_count_lock); - have_waiters = detail->waiters_count > 0; - RtlLeaveCriticalSection (&detail->waiters_count_lock); - - /* If there aren't any waiters, then this is a no-op. */ - if (have_waiters) - NtReleaseSemaphore(detail->sema, 1, NULL); - - return 0; -} - -static int wine_pthread_cond_broadcast(pthread_cond_t *cond) -{ - int have_waiters = 0; - wine_cond_detail *detail; - - if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond); - detail = ((wine_cond)cond)->cond; - - /* - * This is needed to ensure that and are - * consistent relative to each other. - */ - RtlEnterCriticalSection (&detail->waiters_count_lock); - - if (detail->waiters_count > 0) { - /* - * We are broadcasting, even if there is just one waiter... - * Record that we are broadcasting, which helps optimize - * for the non-broadcast case. - */ - detail->was_broadcast = 1; - have_waiters = 1; - } - - if (have_waiters) { - /* Wake up all the waiters atomically. */ - NtReleaseSemaphore(detail->sema, detail->waiters_count, NULL); - - RtlLeaveCriticalSection (&detail->waiters_count_lock); - - /* Wait for all the awakened threads to acquire the counting semaphore. */ - NtWaitForMultipleObjects( 1, &detail->waiters_done, FALSE, FALSE, NULL ); - - /* - * This assignment is okay, even without the held - * because no other waiter threads can wake up to access it. - */ - detail->was_broadcast = 0; - } - else - RtlLeaveCriticalSection (&detail->waiters_count_lock); - return 0; -} - -static int wine_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) -{ - wine_cond_detail *detail; - int last_waiter; - - if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond); - detail = ((wine_cond)cond)->cond; - - /* Avoid race conditions. */ - RtlEnterCriticalSection (&detail->waiters_count_lock); - detail->waiters_count++; - RtlLeaveCriticalSection (&detail->waiters_count_lock); - - RtlLeaveCriticalSection ( ((wine_mutex)mutex)->critsect ); - NtWaitForMultipleObjects( 1, &detail->sema, FALSE, FALSE, NULL ); - - /* Reacquire lock to avoid race conditions. */ - RtlEnterCriticalSection (&detail->waiters_count_lock); - - /* We're no longer waiting... */ - detail->waiters_count--; - - /* Check to see if we're the last waiter after . */ - last_waiter = detail->was_broadcast && detail->waiters_count == 0; - - RtlLeaveCriticalSection (&detail->waiters_count_lock); - - /* - * If we're the last waiter thread during this particular broadcast - * then let all the other threads proceed. - */ - if (last_waiter) NtSetEvent( detail->waiters_done, NULL ); - RtlEnterCriticalSection (((wine_mutex)mutex)->critsect); - return 0; -} - -static int wine_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, - const struct timespec *abstime) -{ - LARGE_INTEGER time; - int last_waiter; - wine_cond_detail *detail; - - if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond); - detail = ((wine_cond)cond)->cond; - - /* Avoid race conditions. */ - RtlEnterCriticalSection (&detail->waiters_count_lock); - detail->waiters_count++; - RtlLeaveCriticalSection (&detail->waiters_count_lock); - - RtlLeaveCriticalSection (((wine_mutex)mutex)->critsect); - - time.QuadPart = (ULONGLONG)abstime->tv_sec * 10000000 + abstime->tv_nsec / 100; - time.QuadPart = -time.QuadPart; - NtWaitForMultipleObjects( 1, &detail->sema, FALSE, FALSE, &time ); - - /* Reacquire lock to avoid race conditions. */ - RtlEnterCriticalSection (&detail->waiters_count_lock); - - /* We're no longer waiting... */ - detail->waiters_count--; - - /* Check to see if we're the last waiter after . */ - last_waiter = detail->was_broadcast && detail->waiters_count == 0; - - RtlLeaveCriticalSection (&detail->waiters_count_lock); - - /* - * If we're the last waiter thread during this particular broadcast - * then let all the other threads proceed. - */ - if (last_waiter) NtSetEvent( detail->waiters_done, NULL ); - RtlEnterCriticalSection (((wine_mutex)mutex)->critsect); - return 0; -} - -/***** MISC *****/ - -static pthread_t wine_pthread_self(void) -{ - return (pthread_t)GetCurrentThreadId(); -} - -static int wine_pthread_equal(pthread_t thread1, pthread_t thread2) -{ - return (DWORD)thread1 == (DWORD)thread2; -} - -static void *wine_get_thread_data(void) -{ - return ntdll_get_thread_data()->pthread_data; -} - -static void wine_set_thread_data( void *data ) -{ - ntdll_get_thread_data()->pthread_data = data; -} - -static const struct wine_pthread_callbacks callbacks = -{ - wine_get_thread_data, /* ptr_get_thread_data */ - wine_set_thread_data, /* ptr_set_thread_data */ - wine_pthread_self, /* ptr_pthread_self */ - wine_pthread_equal, /* ptr_pthread_equal */ - wine_pthread_create, /* ptr_pthread_create */ - wine_pthread_cancel, /* ptr_pthread_cancel */ - wine_pthread_join, /* ptr_pthread_join */ - wine_pthread_detach, /* ptr_pthread_detach */ - wine_pthread_exit, /* ptr_pthread_exit */ - wine_pthread_mutex_init, /* ptr_pthread_mutex_init */ - wine_pthread_mutex_lock, /* ptr_pthread_mutex_lock */ - wine_pthread_mutex_trylock, /* ptr_pthread_mutex_trylock */ - wine_pthread_mutex_unlock, /* ptr_pthread_mutex_unlock */ - wine_pthread_mutex_destroy, /* ptr_pthread_mutex_destroy */ - wine_pthread_rwlock_init, /* ptr_pthread_rwlock_init */ - wine_pthread_rwlock_destroy, /* ptr_pthread_rwlock_destroy */ - wine_pthread_rwlock_rdlock, /* ptr_pthread_rwlock_rdlock */ - wine_pthread_rwlock_tryrdlock, /* ptr_pthread_rwlock_tryrdlock */ - wine_pthread_rwlock_wrlock, /* ptr_pthread_rwlock_wrlock */ - wine_pthread_rwlock_trywrlock, /* ptr_pthread_rwlock_trywrlock */ - wine_pthread_rwlock_unlock, /* ptr_pthread_rwlock_unlock */ - wine_pthread_cond_init, /* ptr_pthread_cond_init */ - wine_pthread_cond_destroy, /* ptr_pthread_cond_destroy */ - wine_pthread_cond_signal, /* ptr_pthread_cond_signal */ - wine_pthread_cond_broadcast, /* ptr_pthread_cond_broadcast */ - wine_pthread_cond_wait, /* ptr_pthread_cond_wait */ - wine_pthread_cond_timedwait /* ptr_pthread_cond_timedwait */ -}; - -static struct wine_pthread_functions pthread_functions; - -void pthread_init(void) -{ - wine_pthread_get_functions( &pthread_functions, sizeof(pthread_functions) ); - pthread_functions.init_process( &callbacks, sizeof(callbacks) ); -} - -#endif /* HAVE_PTHREAD_H */ diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 3fc21346035..a69746c1c8e 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -335,7 +335,6 @@ HANDLE thread_init(void) user_shared_data->TickCountLowDeprecated = user_shared_data->u.TickCount.LowPart; user_shared_data->TickCountMultiplier = 1 << 24; - pthread_init(); return exe_file; }