diff options
-rw-r--r-- | ChangeLog | 15 | ||||
-rw-r--r-- | attr.c | 4 | ||||
-rw-r--r-- | cancel.c | 83 | ||||
-rw-r--r-- | cleanup.c | 209 | ||||
-rw-r--r-- | condvar.c | 203 | ||||
-rw-r--r-- | create.c | 144 | ||||
-rw-r--r-- | dll.c | 76 | ||||
-rw-r--r-- | exit.c | 68 | ||||
-rw-r--r-- | global.c | 76 | ||||
-rw-r--r-- | implement.h | 192 | ||||
-rw-r--r-- | misc.c | 26 | ||||
-rw-r--r-- | private.c | 135 | ||||
-rw-r--r-- | pthread.h | 22 | ||||
-rw-r--r-- | semaphore.c | 3 | ||||
-rw-r--r-- | semaphore.h | 13 | ||||
-rw-r--r-- | sync.c | 191 | ||||
-rw-r--r-- | tsd.c | 203 |
17 files changed, 34 insertions, 1629 deletions
@@ -1,3 +1,12 @@ +Mon Jan 4 11:23:40 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au> + + * all: No code changes, just cleanup. + - remove #if 0 /* Pre Bossom */ enclosed code. + - Remove some redundant #includes. + * pthread.h: Update implemented/unimplemented routines list. + * Tag the bossom merge branch getting ready to merge back to main + trunk. + Tue Dec 29 13:11:16 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au> * implement.h: Move the following struct definitions to pthread.h: @@ -38,6 +47,7 @@ Tue Dec 29 13:11:16 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au> * dll.c: Remove defined(KLUDGE) wrapped code. * fork.c: Remove redefinition of ENOMEM. + Remove pthread_atfork() and fork() with #if 0/#endif. * create.c (pthread_create): Rename threadStart and threadDestroy calls to _pthread_threadStart and _pthread_threadDestroy. @@ -48,6 +58,11 @@ Tue Dec 29 13:11:16 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au> Mon Dec 28 09:54:39 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au> + * semaphore.c: Initial version. From John Bossom's implementation. + * semaphore.h: Initial version. From John Bossom's implementation. + +Mon Dec 28 09:54:39 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au> + * pthread.h (pthread_attr_t_): Change to *pthread_attr_t. * attr.c (pthread_attr_setstacksize): Merge with John Bossom's version. @@ -473,7 +473,3 @@ pthread_attr_setdetachstate(pthread_attr_t *attr, (*attr)->detachstate = detachstate; return 0; } - - - - @@ -5,8 +5,6 @@ * POSIX thread functions related to thread cancellation. */ -#include <errno.h> - #include "pthread.h" #include "implement.h" @@ -242,84 +240,3 @@ pthread_cancel (pthread_t thread) /* </JEB> */ -#if 0 /* Pre Bossom */ - -#include <errno.h> - -#include "pthread.h" -#include "implement.h" - -int -pthread_setcancelstate(int state, - int *oldstate) -{ - pthread_t us = pthread_self(); - - /* Validate the new cancellation state. */ - if (state != PTHREAD_CANCEL_ENABLE - || state != PTHREAD_CANCEL_DISABLE) - { - return EINVAL; - } - - if (oldstate != NULL) - { - *oldstate = us->cancelstate; - } - - us->cancelstate = state; - return 0; -} - -int -pthread_setcanceltype(int type, int *oldtype) -{ - pthread_t us = pthread_self(); - - /* Validate the new cancellation type. */ - if (type == PTHREAD_CANCEL_ASYNCHRONOUS || - type != PTHREAD_CANCEL_DEFERRED) - { - return EINVAL; - } - - if (oldtype != NULL) - { - *oldtype = us->canceltype; - } - - us->canceltype = type; - return 0; -} - -int -pthread_cancel(pthread_t thread) -{ - if (_PTHREAD_VALID(thread) - && thread->ptstatus != _PTHREAD_REUSE) - { - thread->cancel_pending = TRUE; - return 0; - } - - return ESRCH; -} - -void -pthread_testcancel(void) -{ - pthread_t thread = pthread_self(); - - if (thread->cancelstate == PTHREAD_CANCEL_DISABLE) - { - return; - } - - if (thread->cancel_pending == TRUE) - { - pthread_exit(PTHREAD_CANCELED); - } - /* Never reached. */ -} - -#endif /* Pre Bossom */ @@ -6,9 +6,8 @@ * threads. */ -#include <errno.h> - #include <malloc.h> + #include "pthread.h" #include "implement.h" @@ -143,209 +142,3 @@ _pthread_push_cleanup (_pthread_cleanup_t * cleanup, /* </JEB> */ -#if 0 /* Pre Bossom */ - -int -_pthread_handler_push(int stack, - int poporder, - void (*routine)(void *), - void *arg) -{ - /* Place the new handler into the list so that handlers are - popped off in the order given by poporder. */ - _pthread_handler_node_t * new_handler; - _pthread_handler_node_t * next; - _pthread_handler_node_t ** stacktop; - - stacktop = _PTHREAD_STACK(stack); - - new_handler = - (_pthread_handler_node_t *) malloc(sizeof(_pthread_handler_node_t)); - - if (new_handler == NULL) - { - return 0; /* NOMEM */ - } - - new_handler->routine = routine; - new_handler->arg = arg; - - if (poporder == _PTHREAD_HANDLER_POP_LIFO) - { - /* Add the new node to the start of the list. */ - new_handler->next = *stacktop; - *stacktop = new_handler; - } - else - { - /* Add the new node to the end of the list. */ - new_handler->next = NULL; - - if (*stacktop == NULL) - { - *stacktop = new_handler; - } - else - { - next = *stacktop; - - while (next->next != NULL) - { - next = next->next; - } - - next->next = new_handler; - } - } - return 0; -} - -void -_pthread_handler_pop(int stack, int execute) -{ - _pthread_handler_node_t ** stacktop; - _pthread_handler_node_t * next; - void (* func)(void *); - void * arg; - - stacktop = _PTHREAD_STACK(stack); - - if (*stacktop != NULL) - { - func = (*stacktop)->routine; - arg = (*stacktop)->arg; - next = (*stacktop)->next; - - free(*stacktop); - *stacktop = next; - - if (execute != 0 && func != NULL) - { - (void) func(arg); - } - } -} - -void -_pthread_handler_pop_all(int stack, int execute) -{ - /* Pop and possibly run all handlers on the given stack. */ - _pthread_handler_node_t ** stacktop; - _pthread_handler_node_t * next; - void (* func)(void *); - void * arg; - - stacktop = _PTHREAD_STACK(stack); - - while (*stacktop != NULL) - { - func = (*stacktop)->routine; - arg = (*stacktop)->arg; - next = (*stacktop)->next; - - free(*stacktop); - *stacktop = next; - - if (execute != 0 && func != NULL) - { - (void) func(arg); - } - } -} - -/* Run destructors for all non-NULL key values for the calling thread. - */ -void -_pthread_destructor_run_all() -{ - _pthread_tsd_key_t * key; - int count; - int dirty; - - /* This threads private keys */ - key = _pthread_tsd_key_table; - - /* Stop destructor execution at a finite time. POSIX allows us - to ignore this if we like, even at the risk of an infinite loop. - - FIXME: We don't know when to stop yet. - */ - for (count = 0; count < PTHREAD_DESTRUCTOR_ITERATIONS; count++) - { - int k; - void * arg; - - dirty = 0; - - /* Loop through all keys. */ - for (k = 0; k < _POSIX_THREAD_KEYS_MAX; k++) - { - /* CRITICAL SECTION */ - pthread_mutex_lock(&_pthread_tsd_mutex); - - switch (key->status) - { - case _PTHREAD_TSD_KEY_INUSE: - arg = pthread_getspecific((pthread_key_t) k); - - if (arg != NULL && key->destructor != NULL) - { - /* The destructor must be called with the mutex off. */ - pthread_mutex_unlock(&_pthread_tsd_mutex); - /* END CRITICAL SECTION */ - - /* FIXME: Is the destructor supposed to set the key value - to NULL? How is this done when arg is the key value, not - a pointer to it? For now we assume that the destructor - always succeeds. - */ - (void) (key->destructor)(arg); - - /* CRITICAL SECTION */ - pthread_mutex_lock(&_pthread_tsd_mutex); - - pthread_setspecific((pthread_key_t) k, NULL); -#if 0 - /* Only needed if we don't assume the destructor - always succeeds. - */ - dirty = 1; -#endif - } - break; - - case _PTHREAD_TSD_KEY_DELETED: - key->status = _PTHREAD_TSD_KEY_INUSE; - pthread_setspecific((pthread_key_t) k, NULL); - - if (key->in_use <= 0) - { - /* This is the last thread to use this - deleted key. It can now be made available - for re-use. - */ - key->status = _PTHREAD_TSD_KEY_REUSE; - _pthread_key_reuse[_pthread_key_reuse_top++] = k; - } - else - { - key->status = _PTHREAD_TSD_KEY_DELETED; - } - break; - - default: - break; - } - - pthread_mutex_unlock(&_pthread_tsd_mutex); - /* END CRITICAL SECTION */ - - key++; - } - - if (!dirty) - break; - } -} - -#endif /* Pre Bossom */ @@ -9,7 +9,6 @@ * Code contributed by John E. Bossom <JEB>. */ -#include <errno.h> #include <string.h> #include "pthread.h" @@ -705,205 +704,3 @@ pthread_cond_broadcast (pthread_cond_t * cond) /* </JEB> */ - -#if 0 /* Pre Bossom */ - -#include <errno.h> - -#include <windows.h> -#include "pthread.h" - -int -pthread_condattr_init(pthread_condattr_t *attr) -{ - return (attr == NULL) ? EINVAL : 0; -} - -int -pthread_condattr_destroy(pthread_condattr_t *attr) -{ - return (attr == NULL) ? EINVAL : 0; -} - -int -pthread_condattr_setpshared(pthread_condattr_t *attr, - int pshared) -{ - return (attr == NULL) ? EINVAL : ENOSYS; -} - -int -pthread_condattr_getpshared(pthread_condattr_t *attr, - int *pshared) -{ - return (attr == NULL) ? EINVAL : ENOSYS; -} - -int -pthread_cond_init(pthread_cond_t *cv, const pthread_condattr_t *attr) -{ - /* Ensure we have a valid cond_t variable. */ - if (cv == NULL) - { - return EINVAL; - } - - /* Initialize the count to 0. */ - cv->waiters_count = 0; - - /* Initialize the "mutex". FIXME: Check attributes arg. */ - pthread_mutex_init(&cv->waiters_count_lock, NULL); - - /* Create an auto-reset event. */ - cv->events[SIGNAL] = CreateEvent (NULL, /* no security */ - FALSE, /* auto-reset event */ - FALSE, /* non-signaled initially */ - NULL); /* unnamed */ - - /* Create a manual-reset event. */ - cv->events[BROADCAST] = CreateEvent (NULL, /* no security */ - TRUE, /* manual-reset */ - FALSE, /* non-signaled initially */ - NULL); /* unnamed */ - - return 0; -} - -/* This is an internal routine that allows the functions `pthread_cond_wait' and - `pthread_cond_timedwait' to share implementations. The `abstime' - parameter to this function is in millisecond units (or INFINITE). */ - -static int -cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex, DWORD abstime) -{ - int result, last_waiter; - - /* Ensure we have a valid cond_t variable. */ - if (cv == NULL) - { - return EINVAL; - } - - /* CANCELATION POINT */ - pthread_testcancel(); - - /* Avoid race conditions. */ - pthread_mutex_lock(&cv->waiters_count_lock); - cv->waiters_count++; - pthread_mutex_unlock(&cv->waiters_count_lock); - - /* It's okay to release the mutex here since Win32 manual-reset - events maintain state when used with SetEvent(). This avoids the - "lost wakeup" bug. */ - - pthread_mutex_unlock(mutex); - - /* Wait for either event to become signaled due to - pthread_cond_signal() being called or pthread_cond_broadcast() - being called. */ - - result = WaitForMultipleObjects (2, cv->events, FALSE, abstime); - - pthread_mutex_lock (&cv->waiters_count_lock); - cv->waiters_count--; - last_waiter = cv->waiters_count == 0; - pthread_mutex_unlock (&cv->waiters_count_lock); - - /* Some thread called pthread_cond_broadcast(). */ - if ((result == WAIT_OBJECT_0 + BROADCAST) && last_waiter) - { - /* We're the last waiter to be notified, so reset the manual - event. */ - ResetEvent(cv->events[BROADCAST]); - } - - /* Reacquire the mutex. */ - pthread_mutex_lock(mutex); - - return 0; -} - -int -pthread_cond_wait(pthread_cond_t *cv, - pthread_mutex_t *mutex) -{ - return cond_wait(cv, mutex, INFINITE); -} - -/* Assume that our configure script will test for the existence of - `struct timespec' and define it according to POSIX if it isn't - found. This will enable people to use this implementation - without necessarily needing Cygwin32. */ - -int -pthread_cond_timedwait(pthread_cond_t *cv, - pthread_mutex_t *mutex, - const struct timespec *abstime) -{ - DWORD msecs; - - /* Calculate the number of milliseconds in abstime. */ - msecs = abstime->tv_sec * 1000; - msecs += abstime->tv_nsec / 1000000; - - return cond_wait(cv, mutex, msecs); -} - -int -pthread_cond_broadcast (pthread_cond_t *cv) -{ - int have_waiters; - - /* Ensure we have a valid cond_t variable. */ - if (cv == NULL) - { - return EINVAL; - } - - /* Avoid race conditions. */ - pthread_mutex_lock (&cv->waiters_count_lock); - have_waiters = (cv->waiters_count > 0); - pthread_mutex_unlock (&cv->waiters_count_lock); - - if (have_waiters) { - SetEvent(cv->events[BROADCAST]); - } - - return 0; -} - -int -pthread_cond_signal (pthread_cond_t *cv) -{ - int have_waiters; - - /* Ensure we have a valid cond_t variable. */ - if (cv == NULL) - { - return EINVAL; - } - - /* Avoid race conditions. */ - pthread_mutex_lock (&cv->waiters_count_lock); - have_waiters = (cv->waiters_count > 0); - pthread_mutex_unlock (&cv->waiters_count_lock); - - if (have_waiters) { - SetEvent(cv->events[SIGNAL]); - } - - return 0; -} - -int -pthread_cond_destroy(pthread_cond_t *cv) -{ - if (cv == NULL) - { - return EINVAL; - } - - return pthread_mutex_destroy(&cv->waiters_count_lock); -} - -#endif /* Pre Bossom */ @@ -145,147 +145,3 @@ FAIL0: /* </JEB> */ - -#if 0 /* Pre Bossom */ - -#include <errno.h> - -#include <windows.h> -#include <process.h> -#include <string.h> - -#include "pthread.h" -#include "implement.h" - -unsigned -STDCALL _pthread_start_call(void * us_arg) -{ - /* We're now in a running thread. Any local variables here are on - this thread's private stack so we're safe to leave data in them - until we leave. */ - pthread_t us; - - /* FIXME: Needs to be a malloc(PTHREAD_KEYS_MAX) otherwise changing - _PTHREAD_MAX_KEYS in a later version of the DLL will break older apps. - */ - void * keys[_PTHREAD_MAX_KEYS]; - - unsigned (*func)(void *); - void * arg; - unsigned ret; - - us = (pthread_t) us_arg; - - memset(keys, 0, sizeof(keys)); - - (void) TlsSetValue(_pthread_threadID_TlsIndex, (LPVOID) us); - (void) TlsSetValue(_pthread_TSD_keys_TlsIndex, (LPVOID) keys); - - /* FIXME: For now, if priority setting fails then at least ensure - that our records reflect true reality. */ - if (SetThreadPriority((HANDLE) us->win32handle, us->attr.priority) == FALSE) - { - us->attr.priority = GetThreadPriority((HANDLE) us->win32handle); - } - - func = us->call.routine; - arg = us->call.arg; - - ret = (*func)(arg); - - _pthread_exit(us, NULL, ret); - - /* Never Reached */ - return 0; -} - -int -pthread_create(pthread_t *thread, - const pthread_attr_t *attr, - void * (*start_routine) (void *), - void * arg) -{ - HANDLE handle = (HANDLE) NULL; - unsigned flags; - void * security = NULL; - DWORD threadID; - pthread_attr_t * attr_copy; - pthread_t new_thread; - /* Success unless otherwise set. */ - int ret; - - /* CRITICAL SECTION */ - pthread_mutex_lock(&_pthread_table_mutex); - - ret = _pthread_new_thread(&new_thread); - - pthread_mutex_unlock(&_pthread_table_mutex); - /* END CRITICAL SECTION */ - - if (ret == 0) - { - attr_copy = &(new_thread->attr); - - /* Map given attributes otherwise just use default values. */ - if (attr != NULL) - { - if (attr_copy->stacksize == 0) - { - attr_copy->stacksize = PTHREAD_STACK_MIN; - } - - attr_copy->detachstate = attr->detachstate; - attr_copy->priority = attr->priority; - -#if HAVE_SIGSET_T - memcpy(&(attr_copy->sigmask), &(attr->sigmask), sizeof(sigset_t)); -#endif /* HAVE_SIGSET_T */ - } - - /* We call a generic wrapper which then calls the start routine. */ - new_thread->call.routine = (unsigned (*)(void *)) start_routine; - new_thread->call.arg = arg; - - /* Start running, not suspended. */ - flags = 0; - - handle = (HANDLE) _beginthreadex(security, - attr_copy->stacksize, - _pthread_start_call, - (void *) new_thread, - flags, - &threadID); - - if (handle == (HANDLE) NULL) - { - ret = EAGAIN; - } - } - else - { - ret = EAGAIN; - } - - if (ret == 0) - { - /* Let the caller know the thread handle. */ - new_thread->win32handle = handle; - new_thread->ptstatus = _PTHREAD_INUSE; - *thread = new_thread; - } - else - { - /* CRITICAL SECTION */ - pthread_mutex_lock(&_pthread_table_mutex); - - /* Remove the failed thread entry. */ - _pthread_delete_thread(new_thread); - - pthread_mutex_unlock(&_pthread_table_mutex); - /* END CRITICAL SECTION */ - } - - return ret; -} - -#endif /* Pre Bossom */ @@ -5,7 +5,6 @@ * This translation unit implements DLL initialisation. */ -#include <windows.h> #include <malloc.h> #include "pthread.h" #include "implement.h" @@ -102,78 +101,3 @@ DllMain ( return (result); } /* DllMain */ - - - -#if 0 /* Pre Bossom */ - -/* We use the DLL entry point function to set up per thread storage - specifically to hold the threads own thread ID. - - The thread ID is stored by _pthread_start_call(). - - The thread ID is retrieved by pthread_self(). - - */ - -/* Global index for TLS data. */ -DWORD _pthread_threadID_TlsIndex; - -/* Global index for thread TSD key array. */ -DWORD _pthread_TSD_keys_TlsIndex; - - -/* Function pointer to TryEnterCriticalSection if it exists; otherwise NULL */ -BOOL (WINAPI *_pthread_try_enter_critical_section)(LPCRITICAL_SECTION) = NULL; - -/* Handle to kernel32.dll */ -static HINSTANCE _pthread_h_kernel32; - -BOOL WINAPI PthreadsEntryPoint(HINSTANCE dllHandle, - DWORD reason, - LPVOID situation) -{ - - - switch (reason) - { - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - break; - - case DLL_PROCESS_ATTACH: - /* Set up per thread thread ID storage. */ - _pthread_threadID_TlsIndex = TlsAlloc(); - - if (_pthread_threadID_TlsIndex == 0xFFFFFFFF) - { - return FALSE; - } - - /* Set up per thread TSD key array pointer. */ - _pthread_TSD_keys_TlsIndex = TlsAlloc(); - - if (_pthread_TSD_keys_TlsIndex == 0xFFFFFFFF) - { - return FALSE; - } - - /* Load KERNEL32 and try to get address of TryEnterCriticalSection */ - _pthread_h_kernel32 = LoadLibrary(TEXT("KERNEL32.DLL")); - _pthread_try_enter_critical_section = (void *) GetProcAddress(_pthread_h_kernel32, "TryEnterCriticalSection"); - break; - - case DLL_PROCESS_DETACH: - (void) TlsFree(_pthread_TSD_keys_TlsIndex); - (void) TlsFree(_pthread_threadID_TlsIndex); - (void) FreeLibrary(_pthread_h_kernel32); - break; - - default: - return FALSE; - } - - return TRUE; -} - -#endif /* Pre Bossom */ @@ -6,8 +6,6 @@ * a thread. */ -#include <windows.h> -#include <process.h> #include "pthread.h" #include "implement.h" @@ -49,69 +47,3 @@ pthread_exit (void *value_ptr) /* </JEB> */ - -#if 0 /* Pre Bossom */ - -void -_pthread_vacuum(void) -{ - /* Run all the handlers. */ - _pthread_handler_pop_all(_PTHREAD_CLEANUP_STACK, - _PTHREAD_HANDLER_EXECUTE); - - /* Pop any atfork handlers without executing them. */ - _pthread_handler_pop_all(_PTHREAD_FORKPREPARE_STACK, - _PTHREAD_HANDLER_NOEXECUTE); - - _pthread_handler_pop_all(_PTHREAD_FORKPARENT_STACK, - _PTHREAD_HANDLER_NOEXECUTE); - - _pthread_handler_pop_all(_PTHREAD_FORKCHILD_STACK, - _PTHREAD_HANDLER_NOEXECUTE); -} - -void -_pthread_exit(pthread_t thread, void * value, int return_code) -{ - int detachstate; - - /* CRITICAL SECTION */ - pthread_mutex_lock(&_pthread_table_mutex); - - /* Copy value into the thread entry so it can be given - to any joining threads. */ - thread->joinvalueptr = value; - - pthread_mutex_unlock(&_pthread_table_mutex); - /* END CRITICAL SECTION */ - - _pthread_vacuum(); - - /* CRITICAL SECTION */ - pthread_mutex_lock(&_pthread_table_mutex); - - /* Remove the thread entry on exit only if the thread is detached - AND there are no waiting joins. Otherwise the thread entry will - be deleted by the last waiting pthread_join() after this thread - has terminated. */ - - if (pthread_attr_getdetachstate(&thread->attr, &detachstate) == 0 - && detachstate == PTHREAD_CREATE_DETACHED - && thread->join_count == 0) - { - (void) _pthread_delete_thread(thread); - } - - pthread_mutex_unlock(&_pthread_table_mutex); - /* END CRITICAL SECTION */ - - _endthreadex(return_code); -} - -void -pthread_exit(void * value) -{ - _pthread_exit(pthread_self(), value, 0); -} - -#endif /* Pre Bossom */ @@ -6,8 +6,6 @@ * as a whole. */ -#include <windows.h> -#include <process.h> #include "pthread.h" #include "implement.h" @@ -17,77 +15,3 @@ pthread_key_t _pthread_selfThreadKey = NULL; pthread_key_t _pthread_cleanupKey = NULL; -#if 0 /* Pre Bossom */ - -/* POSIX run-time invariant values. (Currently POSIX minimum values) - - Making these constants will mean that applications remain binary - compatible between versions of the DLL. - - FIXME: There are still places in the package that break this. -*/ - -const int _POSIX_THREAD_THREADS_MAX = _PTHREAD_MAX_THREADS; -const int _POSIX_THREAD_DESTRUCTOR_ITERATIONS = 4; -const int _POSIX_THREAD_KEYS_MAX = _PTHREAD_MAX_KEYS; - - -const int _pthread_create_joinable = 0; -const int _pthread_create_detached = 1; - -/* Cancelability attributes */ -const int _pthread_cancel_enable = 0; -const int _pthread_cancel_disable = 1; - -const int _pthread_cancel_asynchronous = 0; -const int _pthread_cancel_deferred = 1; - - -/* Declare variables which are global to all threads in the process. */ - -pthread_mutex_t _pthread_table_mutex = PTHREAD_MUTEX_INITIALIZER; - -DWORD _pthread_threads_count = 0; - -/* Per thread management storage. See comments in private.c */ -/* An array of struct _pthread */ -_pthread_t _pthread_virgins[_PTHREAD_MAX_THREADS]; - -/* Index to the next available previously unused struct _pthread */ -int _pthread_virgin_next = 0; - -/* An array of pointers to struct _pthread */ -pthread_t _pthread_reuse[_PTHREAD_MAX_THREADS]; - -/* Index to the first available reusable pthread_t. */ -int _pthread_reuse_top = -1; - -/* An array of pointers to struct _pthread indexed by hashing - the Win32 handle. */ -pthread_t _pthread_win32handle_map[_PTHREAD_MAX_THREADS]; - -/* Per thread mutex locks. */ -pthread_mutex_t _pthread_threads_mutex_table[_PTHREAD_MAX_THREADS]; - -/* Global TSD key array. */ -_pthread_tsd_key_t _pthread_tsd_key_table[_PTHREAD_MAX_KEYS]; - -/* Mutex lock for TSD operations */ -pthread_mutex_t _pthread_tsd_mutex = PTHREAD_MUTEX_INITIALIZER; - -/* Index to the next available TSD key. */ -int _pthread_tsd_key_next = 0; - -/* An array of pthread_key_t */ -pthread_key_t _pthread_key_virgins[_PTHREAD_MAX_KEYS]; - -/* Index to the next available previously unused pthread_key_t */ -int _pthread_key_virgin_next = 0; - -/* An array of pthread_key_t */ -pthread_key_t _pthread_key_reuse[_PTHREAD_MAX_KEYS]; - -/* Index to the first available reusable pthread_key_t. */ -int _pthread_key_reuse_top; - -#endif /* Pre Bossom */ diff --git a/implement.h b/implement.h index c3be637..6bcedf6 100644 --- a/implement.h +++ b/implement.h @@ -172,196 +172,4 @@ void _pthread_tkAssocDestroy (ThreadKeyAssoc * assoc); /* </JEB> */ - -#if 0 /* Pre Bossom */ - -/* Use internally to initialise const ints and thread admin array sizes. */ -#define _PTHREAD_MAX_THREADS 128 -#define _PTHREAD_MAX_KEYS 128 - -#define _PTHREAD_HASH_INDEX(x) (((ULONG) x) % PTHREAD_THREADS_MAX) - -enum { - _PTHREAD_NEW, - _PTHREAD_INUSE, - _PTHREAD_EXITED, - _PTHREAD_REUSE -}; - -enum { - _PTHREAD_TSD_KEY_DELETED, - _PTHREAD_TSD_KEY_INUSE, - _PTHREAD_TSD_KEY_REUSE -}; - -#define _PTHREAD_VALID(T) \ - ((T) != NULL \ - && ((T)->ptstatus == _PTHREAD_NEW \ - || (T)->ptstatus == _PTHREAD_INUSE)) - -/* Handler execution flags. */ -#define _PTHREAD_HANDLER_NOEXECUTE 0 -#define _PTHREAD_HANDLER_EXECUTE 1 - -/* Special value to mark attribute objects as valid. */ -#define _PTHREAD_ATTR_VALID 0xC0FFEE - -/* General description of a handler function on a stack. */ -typedef struct _pthread_handler_node _pthread_handler_node_t; - -struct _pthread_handler_node { - _pthread_handler_node_t * next; - void (* routine)(void *); - void * arg; -}; - -/* TSD key element. */ -typedef struct _pthread_tsd_key _pthread_tsd_key_t; - -struct _pthread_tsd_key { - int in_use; - int status; - void (* destructor)(void *); -}; - -/* Stores a thread call routine and argument. */ -typedef struct { - unsigned (*routine)(void *); - void * arg; -} _pthread_call_t; - -/* Macro to compute the address of a given handler stack. */ -#define _PTHREAD_STACK(stack) \ - ((_pthread_handler_node_t **) &(pthread_self()->cleanupstack) + stack); - -/* Macro to compute the table index of a thread entry from it's entry - address. */ -#define _PTHREAD_THREADS_TABLE_INDEX(this) \ - ((_pthread_threads_table_t *) this - \ - (_pthread_threads_table_t *) _pthread_threads_threads_table) - -/* Macro to compute the address of a per-thread mutex lock. */ -#define _PTHREAD_THREAD_MUTEX(this) \ - (&_pthread_threads_mutex_table[_PTHREAD_THREADS_TABLE_INDEX(this)]) - -/* An element in the thread table. */ -typedef struct _pthread _pthread_t; - -/* Keep the old typedef until we've updated all source files. */ -typedef struct _pthread _pthread_threads_thread_t; - -/* Related constants */ -struct _pthread { - HANDLE win32handle; - int ptstatus; /* _PTHREAD_EXITED - _PTHREAD_REUSABLE */ - pthread_attr_t attr; - _pthread_call_t call; - int cancel_pending; - int cancelstate; /* PTHREAD_CANCEL_DISABLE - PTHREAD_CANCEL_ENABLE */ - - int canceltype; /* PTHREAD_CANCEL_ASYNCHRONOUS - PTHREAD_CANCEL_DEFERRED */ - void ** joinvalueptr; - int join_count; - - /* These must be kept in this order and together. */ - _pthread_handler_node_t * cleanupstack; - _pthread_handler_node_t * forkpreparestack; - _pthread_handler_node_t * forkparentstack; - _pthread_handler_node_t * forkchildstack; -}; - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Generic handler push and pop routines. */ - -int _pthread_handler_push(int stack, - int poporder, - void (*routine)(void *), - void *arg); - -void _pthread_handler_pop(int stack, - int execute); - -void _pthread_handler_pop_all(int stack, - int execute); - -void _pthread_destructor_run_all(); - -/* Primitives to manage threads table entries. */ - -int _pthread_new_thread(pthread_t * thread); - -int _pthread_delete_thread(pthread_t thread); - -/* Thread cleanup. */ - -void _pthread_vacuum(void); - -void _pthread_exit(pthread_t thread, void * value, int return_code); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - - -/* Global declared dll.c */ - -extern DWORD _pthread_threadID_TlsIndex; - -extern DWORD _pthread_TSD_keys_TlsIndex; - - -/* Global data declared in global.c */ - -extern pthread_mutex_t _pthread_table_mutex; - -extern DWORD _pthread_threads_count; - -/* An array of struct _pthread */ -extern _pthread_t _pthread_virgins[]; - -/* Index to the next available previously unused struct _pthread */ -extern int _pthread_virgin_next; - -/* An array of pointers to struct _pthread */ -extern pthread_t _pthread_reuse[]; - -/* Index to the first available reusable pthread_t. */ -extern int _pthread_reuse_top; - -/* An array of pointers to struct _pthread indexed by hashing - the Win32 handle. */ -extern pthread_t _pthread_win32handle_map[]; - -/* Per thread mutex locks. */ -extern pthread_mutex_t _pthread_threads_mutex_table[]; - -/* Global TSD key array. */ -extern _pthread_tsd_key_t _pthread_tsd_key_table[]; - -/* Mutex lock for TSD operations */ -extern pthread_mutex_t _pthread_tsd_mutex; - -/* Function pointer to TryEnterCriticalSection if it exists; otherwise NULL */ -extern BOOL (WINAPI *_pthread_try_enter_critical_section)(LPCRITICAL_SECTION); - -/* An array of pthread_key_t */ -extern pthread_key_t _pthread_key_virgins[]; - -/* Index to the next available previously unused pthread_key_t */ -extern int _pthread_key_virgin_next; - -/* An array of pthread_key_t */ -extern pthread_key_t _pthread_key_reuse[]; - -/* Index to the first available reusable pthread_key_t. */ -extern int _pthread_key_reuse_top; - -#endif /* Pre Bossom */ - #endif /* _IMPLEMENT_H */ @@ -246,29 +246,3 @@ pthreadCancelableWait (HANDLE waitHandle) /* </JEB> */ -#if 0 /* Pre Bossom */ - -pthread_t -pthread_self(void) -{ - pthread_t ret; - /* This TLS index is allocated on DLL load by dll.c */ - extern DWORD _pthread_threadID_TlsIndex; - - ret = (pthread_t) TlsGetValue(_pthread_threadID_TlsIndex); - - if (ret == 0) - { - /* FIXME: Oh no! This can't happen. */ - } - - return ret; -} - -int -pthread_equal(pthread_t t1, pthread_t t2) -{ - return (t1 == t2); -} - -#endif /* Pre Bossom */ @@ -417,138 +417,3 @@ _pthread_callUserDestroyRoutines (pthread_t thread) /* </JEB> */ - -#if 0 /* Pre Bossom */ - -/* Thread ID management. - --------------------- - - We started by simply mapping the Win32 thread handle directly to - pthread_t. However, in order to process pthread_join()'s, we need - to be able to keep our POSIX thread ID (pthread_t) around after the - Win32 thread has terminated. Win32 may reuse the Win32 handle during that - time, which will conflict. - - The pthread_t value is now actually the pointer to a thread struct: - - typedef struct _pthread * pthread_t; - - which amongst other things stores the Win32 thread handle: - - struct _pthread { - HANDLE win32handle; - int ptstatus; - ... - }; - - So now whereever we need to use the Win32 handle it can be accessed - as: - - pthread_t T = pthread_this(); - HANDLE H; - - H = T->win32handle; - - // or (which is NOT preferred, let the compiler optimise to this). - - H = (HANDLE) *T; - - - POSIX Threads Table - ------------------- - - Having the thread ID as a pointer to the thread struct itself - avoids the need to search the threads table in all but the initial - occasion where we create the thread. - - Initially we used a hash function to select a free thread struct - from the table, possibly needing a walk through the table if the - hash collided with an already in-use thread. - - The scheme used now is more efficient and is done as follows: - - We use two tables and two counters: - - struct _pthread _pthread_virgins[PTHREAD_THREADS_MAX]; - pthread_t _pthread_reuse[PTHREAD_THREADS_MAX]; - - int _pthread_virgin_next = 0; - int _pthread_reuse_top = -1; - - The counter _pthread_virgin_next is an index into _pthread_virgins[], - which can be thought of as a list, and _pthread_reuse_top is an - index into _pthread_reuse[], which can be thought of as a LIFO stack. - - Once taken from _pthread_virgins[], used and freed threads are only - ever pushed back onto _pthread_reuse[]. - - */ - -int -_pthread_new_thread(pthread_t * thread) -{ - pthread_t new_thread; - - if (_pthread_reuse_top >= 0) - { - new_thread = _pthread_reuse[_pthread_reuse_top--]; - } - else - { - if (_pthread_virgin_next < PTHREAD_THREADS_MAX) - { - new_thread = (pthread_t) &_pthread_virgins[_pthread_virgin_next++]; - } - else - { - return EAGAIN; - } - } - - new_thread->win32handle = (HANDLE) NULL; - new_thread->ptstatus = _PTHREAD_NEW; - pthread_attr_init(&(new_thread->attr)); - new_thread->joinvalueptr = NULL; - new_thread->cancelstate = PTHREAD_CANCEL_ENABLE; - new_thread->canceltype = PTHREAD_CANCEL_DEFERRED; - new_thread->cancel_pending = FALSE; - new_thread->cleanupstack = NULL; - new_thread->forkpreparestack = NULL; - new_thread->forkparentstack = NULL; - new_thread->forkchildstack = NULL; - - *thread = new_thread; - _pthread_threads_count++; - - return 0; -} - -int -_pthread_delete_thread(_pthread_t * thread) -{ - /* We don't check that the thread has been properly cleaned up, so - it had better be done already. */ - - /* Release any keys */ - - _pthread_destructor_run_all(); - - /* Remove the thread entry if necessary. */ - - if (thread != NULL - && thread->ptstatus == _PTHREAD_EXITED) - { - pthread_attr_destroy(&(thread->attr)); - thread->win32handle = (HANDLE) NULL; - thread->ptstatus = _PTHREAD_REUSE; - - _pthread_reuse[++_pthread_reuse_top] = thread; - _pthread_threads_count--; - - return 0; - } - - return EINVAL; -} - -#endif /* Pre Bossom */ @@ -100,6 +100,21 @@ * --------------------------- * pthreadCancelableWait * + * --------------------------- + * RealTime Scheduling: + * --------------------------- + * pthread_attr_getschedparam + * pthread_attr_setschedparam + * pthread_getschedparam + * pthread_setschedparam + * sched_get_priority_max + * sched_get_priority_min + * + * --------------------------- + * Signals: + * --------------------------- + * pthread_sigmask + * * Limitations * =========== * The following functions are not implemented: @@ -108,23 +123,17 @@ * RealTime Scheduling: * --------------------------- * pthread_attr_getinheritsched - * pthread_attr_getschedparam * pthread_attr_getschedpolicy * pthread_attr_getscope * pthread_attr_setinheritsched - * pthread_attr_setschedparam * pthread_attr_setschedpolicy * pthread_attr_setscope - * pthread_getschedparam * pthread_mutex_getprioceiling * pthread_mutex_setprioceiling * pthread_mutex_attr_getprioceiling * pthread_mutex_attr_getprotocol * pthread_mutex_attr_setprioceiling * pthread_mutex_attr_setprotocol - * pthread_setschedparam - * sched_get_priority_max - * sched_get_priority_min * * --------------------------- * Fork Handlers: @@ -155,7 +164,6 @@ * Signals: * --------------------------- * pthread_kill - * pthread_sigmask * sigtimedwait * sigwait * sigwaitinfo diff --git a/semaphore.c b/semaphore.c index 04e99f5..c163336 100644 --- a/semaphore.c +++ b/semaphore.c @@ -1,8 +1,6 @@ /* * ------------------------------------------------------------- * - * $Header: /cvs/pthreads-win32/pthreads/semaphore.c,v 1.1.2.1 1998/12/28 23:01:14 rpj Exp $ - * * Module: semaphore.c * * Purpose: @@ -45,7 +43,6 @@ #include "semaphore.h" - int sem_init (sem_t * sem, int pshared, unsigned int value) /* diff --git a/semaphore.h b/semaphore.h index 7b9d352..5eeaf3c 100644 --- a/semaphore.h +++ b/semaphore.h @@ -1,8 +1,6 @@ /* * ------------------------------------------------------------- * - * $Header: /cvs/pthreads-win32/pthreads/semaphore.h,v 1.1.2.1 1998/12/28 23:01:15 rpj Exp $ - * * Module: semaphore.h * * Purpose: @@ -22,17 +20,6 @@ * instead of -1 for failure when checking the status of * these functions. * - * Disclaimer: - * This software is provided "as is". - * - * The author makes no warranty or representation, either - * express or implied, with respect to this software, its - * quality, performance, merchantability, or fitness for a - * particular purpose. In no event will the author be - * liable for direct, indirect, special, incidental, or - * consequential damages arising out of the use or inability - * to use the software. - * * ------------------------------------------------------------- */ #if !defined( SEMAPHORE_H ) @@ -6,13 +6,13 @@ * synchronisation. */ +#include "pthread.h" +#include "implement.h" + /* * Code contributed by John E. Bossom <JEB>. */ -#include "pthread.h" -#include "implement.h" - int pthread_detach (pthread_t tid) /* @@ -125,188 +125,3 @@ pthread_join (pthread_t thread, void **value_ptr) /* </JEB> */ - -#if 0 /* Pre Bossom */ - -#include <errno.h> - -/* POSIX STANDARD: A thread may pass a value pointer to some data via - pthread_exit(). That pointer will be stored in a location supplied - as an argument to pthread_join(). - - IMPLEMENTATION: The value_ptr is stored in the thread entry. When - pthread_join() wakes up after waiting, or immediately if the target - thread has already terminated but is not detached, the value - pointer from pthread_exit() will be copied to *value_ptr. - - If the target thread does not become detached in the mean time, all - waiting joins on that thread will get the value pointer. The last - waiting join will delete the target thread entry. - - ---- - - POSIX STANDARD: The results of multiple simultaneous calls to - pthread_join() specifying the same target thread are undefined. - - IMPLEMENTATION: Any such join that occurs before the first such - join wakes up, or the thread is otherwise detached (by a call to - pthread_detach), will return successfully with the value that was - passed to pthread_exit(). After the last such join returns, the - target thread will have be detached and it's entry removed from the - thread table. - - Until the target thread entry is deleted it will be counted against - {PTHREAD_COUNT_MAX}. - - ---- - - ---- - - POSIX STANDARD: It is unspecified whether a thread that has exited - but remains unjoined counts against {PTHREAD_COUNT_MAX}. - - IMPLEMENTATION: A thread that has exited but remains unjoined will - be counted against {PTHREAD_COUNT_MAX}. The first call to - pthread_join() or pthread_detach() will remove the target thread's - table entry and decrement the count. - - ---- */ - -#include <windows.h> -#include "pthread.h" -#include "implement.h" - -int -pthread_join(pthread_t thread, void ** valueptr) -{ - int detachstate; - - /* First check if we are trying to join to ourselves. */ - if (thread == pthread_self()) - { - return EDEADLK; - } - - if (thread != NULL) - { - int ret; - - /* CRITICAL SECTION */ - pthread_mutex_lock(&_pthread_table_mutex); - - /* If the thread is in DETACHED state, then join will return - immediately. */ - - if (pthread_attr_getdetachstate(&(thread->attr), &detachstate) != 0 - || detachstate == PTHREAD_CREATE_DETACHED) - { - return EINVAL; - } - - thread->join_count++; - - pthread_mutex_unlock(&_pthread_table_mutex); - /* END CRITICAL SECTION */ - - /* CANCELATION POINT */ - pthread_testcancel(); - - /* Wait on the kernel thread object. */ - switch (WaitForSingleObject(thread->win32handle, INFINITE)) - { - case WAIT_FAILED: - /* The thread does not exist. */ - return ESRCH; - case WAIT_OBJECT_0: - /* The thread has finished. */ - break; - default: - /* This should never happen. */ - break; - } - - /* We know the target thread entry still exists at this point - because we incremented join_count above after checking. The - thread entry will not be removed until join_count == 0 again, - ie. when the last waiting join has passed through the - following critical section. */ - - /* CRITICAL SECTION */ - pthread_mutex_lock(&_pthread_table_mutex); - - /* Collect the value pointer passed to pthread_exit(). If - another thread detaches our target thread while we're - waiting, then we report a deadlock as it likely that storage - pointed to by thread->joinvalueptr has been freed or - otherwise no longer valid. */ - - if (pthread_attr_getdetachstate(&(thread->attr), &detachstate) != 0 - || detachstate == PTHREAD_CREATE_DETACHED) - { - ret = EDEADLK; - } - else - { - *valueptr = thread->joinvalueptr; - ret = 0; - } - - thread->join_count--; - - /* If we're the last join to return then we are responsible for - removing the target thread's table entry. */ - if (thread->join_count == 0) - { - ret = _pthread_delete_thread(thread); - } - - pthread_mutex_unlock(&_pthread_table_mutex); - /* END CRITICAL SECTION */ - - return ret; - } - - /* Thread not found. */ - return ESRCH; -} - -int -pthread_detach(pthread_t thread) -{ - int detachstate; - int ret; - - /* CRITICAL SECTION */ - pthread_mutex_lock(&_pthread_table_mutex); - - if (thread == NULL) - { - ret = ESRCH; - } - else - { - /* Check that we can detach this thread. */ - if (pthread_attr_getdetachstate(&(thread->attr), &detachstate) != 0 - || detachstate == PTHREAD_CREATE_DETACHED) - { - ret = EINVAL; - } - else - { - /* This is all we do here - the rest is done either when the - thread exits or when pthread_join() exits. Once this is - set it will never be unset. */ - pthread_attr_setdetachstate(&(thread->attr), - PTHREAD_CREATE_DETACHED); - - ret = 0; - } - } - - pthread_mutex_unlock(&_pthread_table_mutex); - /* END CRITICAL SECTION */ - - return ret; -} - -#endif /* Pre Bossom */ @@ -5,49 +5,6 @@ * POSIX thread functions which implement thread-specific data (TSD). */ -/* - * Why we can't use Win32 TLS - * -------------------------- - * - * In a word: Destructors - * - * POSIX 1003.1 1996, Section 17 allows for optional destructor functions - * to be associated with each key value. - * - * This is my (revised) understanding of how destructors work: - * - * A key is created by a single thread, which then provides in every - * existing thread a TSD matching the same key, but initialised - * to NULL. Each new thread will also get a matching key with value NULL. - * The creating thread can optionally associate a function, called a - * destructor, with the key. - * - * When each thread exits, it calls the destructor function, which - * will then perform an action on that threads key value - * only. (Previously I thought that only the key creating thread ran - * the destructor on the key in all threads. That proposition is - * sounding scarier by the minute.) - * - * SOME APPROACHES TO MANAGING TSD MEMORY - * - * We could simply allocate enough memory on process startup to hold - * all possible data for all possible threads. - * - * We could allocate memory for just a table to hold a single pointer - * for each of POSIX_THREAD_KEYS_MAX keys. pthread_key_create() could then - * allocate space for POSIX_THREADS_MAX key values in one hit and store - * the location of the array in the first table. - * - * The standard also suggests that each thread might store key/value pairs - * on its private stack. This seems like a good idea. I had concerns about - * memory leaks and key re-use if a key was deleted, but the standard talks - * at length on this and basically says it's up to the application to - * make sure everything goes smoothly here, making sure that proper cleanup - * is done before a key is deleted. (section B.17.1.3 in particular) - * - * One more thing to note: destructors must never be called on deleted keys. - */ - #include "pthread.h" #include "implement.h" @@ -351,163 +308,3 @@ pthread_getspecific (pthread_key_t key) /* </JEB> */ - -#if 0 /* Pre Bossom */ - -#include <errno.h> - -#include "pthread.h" -#include "implement.h" - -int -pthread_key_create(pthread_key_t *key, void (*destructor)(void *)) -{ - pthread_key_t k; - int ret = 0; - - /* CRITICAL SECTION */ - pthread_mutex_lock(&_pthread_tsd_mutex); - - if (_pthread_key_reuse_top >= 0) - { - k = _pthread_key_reuse[_pthread_key_reuse_top--]; - } - else - { - if (_pthread_key_virgin_next < PTHREAD_KEYS_MAX) - { - k = _pthread_key_virgins[_pthread_key_virgin_next++]; - } - else - { - return EAGAIN; - } - } - - /* FIXME: This needs to be implemented as a list plus a re-use stack as for - thread IDs. _pthread_destructor_run_all() then needs to be changed - to push keys onto the re-use stack. - */ - - _pthread_tsd_key_table[k].in_use = 0; - _pthread_tsd_key_table[k].status = _PTHREAD_TSD_KEY_INUSE; - _pthread_tsd_key_table[k].destructor = destructor; - - pthread_mutex_unlock(&_pthread_tsd_mutex); - /* END CRITICAL SECTION */ - - *key = k; - - return ret; -} - -int -pthread_setspecific(pthread_key_t key, void *value) -{ - void ** keys; - int inuse; - - /* CRITICAL SECTION */ - pthread_mutex_lock(&_pthread_tsd_mutex); - - inuse = (_pthread_tsd_key_table[key].status == _PTHREAD_TSD_KEY_INUSE); - - pthread_mutex_unlock(&_pthread_tsd_mutex); - /* END CRITICAL SECTION */ - - if (! inuse) - return EINVAL; - - keys = (void **) TlsGetValue(_pthread_TSD_keys_TlsIndex); - - if (keys[key] != NULL) - { - if (value == NULL) - { - /* Key is no longer in use by this thread. */ - _pthread_tsd_key_table[key].in_use--; - } - } - else - { - if (value != NULL) - { - /* Key is now in use by this thread. */ - _pthread_tsd_key_table[key].in_use++; - } - } - - keys[key] = value; - - return 0; -} - -void * -pthread_getspecific(pthread_key_t key) -{ - void ** keys; - int inuse; - - /* CRITICAL SECTION */ - pthread_mutex_lock(&_pthread_tsd_mutex); - - inuse = (_pthread_tsd_key_table[key].status == _PTHREAD_TSD_KEY_INUSE); - - pthread_mutex_unlock(&_pthread_tsd_mutex); - /* END CRITICAL SECTION */ - - if (! inuse) - return (void *) NULL; - - keys = (void **) TlsGetValue(_pthread_TSD_keys_TlsIndex); - return keys[key]; -} - -/* - pthread_key_delete: - - ANSI/IEEE Std 1003.1, 1996 Edition - - Section 17.1.3.2 - - This function deletes a thread-specific data key previously returned by - pthread_key_create(). The thread specific data values associated with - "key" need not be NULL at the time pthread_key_delete() is called. It is - the responsibility of the application to free any application storage - or perform any cleanup actions for data structures related to the deleted - key or associated thread-specific data in any threads; this cleanup - can be done either before or after pthread_key_delete() is called. Any - attempt to use "key" following the call to pthread_key_delete() - results in undefined behaviour. - - The pthread_key_delete() function shall be callable from within - destructor functions. No destructor functions shall be invoked by - pthread_key_delete(). Any destructor function that may have been associated - with "key" shall no longer be called upon thread exit. - */ - -int -pthread_key_delete(pthread_key_t key) -{ - int ret = 0; - - /* CRITICAL SECTION */ - pthread_mutex_lock(&_pthread_tsd_mutex); - - if (_pthread_tsd_key_table[key].status != _PTHREAD_TSD_KEY_INUSE) - { - ret = EINVAL; - } - else - { - _pthread_tsd_key_table[key].status = _PTHREAD_TSD_KEY_DELETED; - _pthread_tsd_key_table[key].destructor = NULL; - } - - pthread_mutex_unlock(&_pthread_tsd_mutex); - /* END CRITICAL SECTION */ - - return ret; -} - -#endif /* Pre Bossom */ |