From 95aa0a376d93ee021a6c085c71418e9f16513e0a Mon Sep 17 00:00:00 2001 From: rpj Date: Tue, 22 Dec 1998 15:59:24 +0000 Subject: Sun Dec 20 14:51:58 1998 Ross Johnson * misc.c (pthreadCancelableWait): New function by John Bossom. Non-stand ard but provides a hook that can be used to implement cancellation points in applications that use this library. * pthread.h (pthread_cleanup_pop): C++ (non-WIN32) version uses try/catch to emulate John Bossom's WIN32 __try/__finally behaviour. In the WIN32 version __finally block, add a test for AbnormalTermination otherwise cleanup is only run if the cleanup_pop execute arg is non-zero. Cancella tion should cause the cleanup to run irrespective of the execute arg. * condvar.c (pthread_condattr_init): Replaced by John Bossom's version. (pthread_condattr_destroy): Replaced by John Bossom's version. (pthread_condattr_getpshared): Replaced by John Bossom's version. (pthread_condattr_setpshared): Replaced by John Bossom's version. (pthread_cond_init): Replaced by John Bossom's version. Fix comment (refered to mutex rather than condition variable). (pthread_cond_destroy): Replaced by John Bossom's version. (pthread_cond_wait): Replaced by John Bossom's version. (pthread_cond_timedwait): Replaced by John Bossom's version. (pthread_cond_signal): Replaced by John Bossom's version. (pthread_cond_broadcast): Replaced by John Bossom's version. Thu Dec 17 19:10:46 1998 Ross Johnson * tsd.c (pthread_key_create): Replaced by John Bossom's version. (pthread_key_delete): Replaced by John Bossom's version. (pthread_setspecific): Replaced by John Bossom's version. (pthread_getspecific): Replaced by John Bossom's version. Mon Dec 7 09:44:40 1998 Ross Johnson * cancel.c (pthread_setcancelstate): Replaced by John Bossom's version. (pthread_setcanceltype): Replaced by John Bossom's version. (pthread_testcancel): Replaced by John Bossom's version. (pthread_cancel): Replaced by John Bossom's version. * exit.c (pthread_exit): Replaced by John Bossom's version. * misc.c (pthread_self): Replaced by John Bossom's version. (pthread_equal): Replaced by John Bossom's version. * sync.c (pthread_detach): Replaced by John Bossom's version. (pthread_join): Replaced by John Bossom's version. * create.c (pthread_create): Replaced by John Bossom's version. * private.c (_pthread_processInitialize): New by John Bossom. (_pthread_processTerminate): Non-public function by John Bossom. (_pthread_threadStart): Non-public function by John Bossom. (_pthread_threadDestroy): Non-public function by John Bossom. (_pthread_cleanupStack): Non-public function by John Bossom. (_pthread_tkAssocCreate): Non-public function by John Bossom. (_pthread_tkAssocDestroy): Non-public function by John Bossom. (_pthread_callUserDestroyRoutines): Non-public function by John Bossom. * implement.h: Added John Bossom's non-API structures and declarations. * dll.c (PthreadsEntryPoint): Cast return value of GetProcAddress to resolve compile warning from MSVC. * dll.c (DLLmain): Replaced by John Bossom's version. * dll.c (PthreadsEntryPoint): Re-applied Anders Norlander's patch:- Initialize _pthread_try_enter_critical_section at startup and release kernel32 handle when DLL is being unloaded. --- private.c | 411 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 411 insertions(+) (limited to 'private.c') diff --git a/private.c b/private.c index 32116ef..9891660 100644 --- a/private.c +++ b/private.c @@ -11,6 +11,415 @@ #include "pthread.h" #include "implement.h" +/* + * Code contributed by John E. Bossom . + */ + +int +_pthread_processInitialize (void) + /* + * ------------------------------------------------------ + * DOCPRIVATE + * This function performs process wide initialization for + * the pthread library. + * + * PARAMETERS + * N/A + * + * DESCRIPTION + * This function performs process wide initialization for + * the pthread library. + * If successful, this routine sets the global variable + * _pthread_processInitialized to TRUE. + * + * RESULTS + * TRUE if successful, + * FALSE otherwise + * + * ------------------------------------------------------ + */ +{ + _pthread_processInitialized = TRUE; + + /* + * Initialize Keys + */ + if ((pthread_key_create (&_pthread_selfThreadKey, NULL) != 0) || + (pthread_key_create (&_pthread_cleanupKey, NULL) != 0)) + { + + _pthread_processTerminate (); + } + + return (_pthread_processInitialized); + +} /* processInitialize */ + +void +_pthread_processTerminate (void) + /* + * ------------------------------------------------------ + * DOCPRIVATE + * This function performs process wide termination for + * the pthread library. + * + * PARAMETERS + * N/A + * + * DESCRIPTION + * This function performs process wide termination for + * the pthread library. + * This routine sets the global variable + * _pthread_processInitialized to FALSE + * + * RESULTS + * N/A + * + * ------------------------------------------------------ + */ +{ + if (_pthread_processInitialized) + { + + if (_pthread_selfThreadKey != NULL) + { + /* + * Release _pthread_selfThreadKey + */ + pthread_key_delete (_pthread_selfThreadKey); + + _pthread_selfThreadKey = NULL; + } + + if (_pthread_cleanupKey != NULL) + { + /* + * Release _pthread_cleanupKey + */ + pthread_key_delete (_pthread_cleanupKey); + + _pthread_cleanupKey = NULL; + } + + _pthread_processInitialized = FALSE; + } + +} /* processTerminate */ + + + +void * +_pthread_threadStart (ThreadParms * threadParms) +{ + pthread_t tid; + void *(*start) (void *); + void *arg; + + int status; + + tid = threadParms->tid; + start = threadParms->start; + arg = threadParms->arg; + + free (threadParms); + + pthread_setspecific (_pthread_selfThreadKey, tid); + + __try + { + /* + * Run the caller's routine; + */ + (*start) (arg); + status = 0; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + /* + * A system unexpected exception had occurred running the user's + * routine. We get control back within this block. + */ + status = -1; + } + + pthread_exit ((void *) status); + + return ((void *) status); + +} /* threadStart */ + + +void +_pthread_threadDestroy (pthread_t thread) +{ + if (thread != NULL) + { + + callUserDestroyRoutines (thread); + + if (thread->cancelEvent != NULL) + { + CloseHandle (thread->cancelEvent); + } + + free (thread); + } + +} /* threadDestroy */ + +#if defined( KLUDGE ) + +void +_pthread_cleanupStack (void) +{ + while (pthread_pop_cleanup (1)) + { + } + +} /* cleanupStack */ + +#endif /* KLUDGE */ + +int +_pthread_tkAssocCreate (ThreadKeyAssoc ** assocP, + pthread_t thread, + pthread_key_t key) + /* + * ------------------------------------------------------------------- + * This routine creates an association that + * is unique for the given (thread,key) combination.The association + * is referenced by both the thread and the key. + * This association allows us to determine what keys the + * current thread references and what threads a given key + * references. + * See the detailed description + * at the beginning of this file for further details. + * + * Notes: + * 1) New associations are pushed to the beginning of the + * chain so that the internal _pthread_selfThreadKey association + * is always last, thus allowing selfThreadExit to + * be implicitly called by pthread_exit last. + * + * Parameters: + * assocP + * address into which the association is returned. + * thread + * current running thread. If NULL, then association + * is only added to the key. A NULL thread indicates + * that the user called pthread_setspecific prior + * to starting a thread. That's ok. + * key + * key on which to create an association. + * Returns: + * 0 - if successful, + * -1 - general error + * ------------------------------------------------------------------- + */ +{ + int result; + ThreadKeyAssoc *assoc; + + /* + * Have to create an association and add it + * to both the key and the thread. + */ + assoc = (ThreadKeyAssoc *) + calloc (1, sizeof (*assoc)); + + if (assoc == NULL) + { + result = -1; + goto FAIL0; + } + + if ((result = pthread_mutex_init (&(assoc->lock), NULL)) != + 0) + { + goto FAIL1; + } + + assoc->thread = thread; + assoc->key = key; + + /* + * Register assoc with key + */ + if ((result = pthread_mutex_lock (&(key->threadsLock))) != + 0) + { + goto FAIL2; + } + + assoc->nextThread = (ThreadKeyAssoc *) key->threads; + key->threads = (void *) assoc; + + pthread_mutex_unlock (&(key->threadsLock)); + + if (thread != NULL) + { + /* + * Register assoc with thread + */ + assoc->nextKey = (ThreadKeyAssoc *) thread->keys; + thread->keys = (void *) assoc; + } + + *assocP = assoc; + + return (result); + + /* + * ------------- + * Failure Code + * ------------- + */ +FAIL2: + pthread_mutex_destroy (&(assoc->lock)); + +FAIL1: + free (assoc); + +FAIL0: + + return (result); + +} /* tkAssocCreate */ + + +void +_pthread_tkAssocDestroy (ThreadKeyAssoc * assoc) + /* + * ------------------------------------------------------------------- + * This routine releases all resources for the given ThreadKeyAssoc + * once it is no longer being referenced + * ie) both the key and thread have stopped referencing it. + * + * Parameters: + * assoc + * an instance of ThreadKeyAssoc. + * Returns: + * N/A + * ------------------------------------------------------------------- + */ +{ + + if ((assoc != NULL) && + (assoc->key == NULL && assoc->thread == NULL)) + { + + pthread_mutex_destroy (&(assoc->lock)); + + free (assoc); + } + +} /* tkAssocDestroy */ + + +void +_pthread_callUserDestroyRoutines (pthread_t thread) + /* + * ------------------------------------------------------------------- + * DOCPRIVATE + * + * This the routine runs through all thread keys and calls + * the destroy routines on the user's data for the current thread. + * It simulates the behaviour of POSIX Threads. + * + * PARAMETERS + * thread + * an instance of pthread_t + * + * RETURNS + * N/A + * ------------------------------------------------------------------- + */ +{ + ThreadKeyAssoc **nextP; + ThreadKeyAssoc *assoc; + + if (thread != NULL) + { + /* + * Run through all Thread<-->Key associations + * for the current thread. + * If the pthread_key_t still exits (ie the assoc->key + * is not NULL) then call the user's TSD destroy routine. + * Notes: + * If assoc->key is NULL, then the user previously called + * PThreadKeyDestroy. The association is now only referenced + * by the current thread and must be released; otherwise + * the assoc will be destroyed when the key is destroyed. + */ + nextP = (ThreadKeyAssoc **) & (thread->keys); + assoc = *nextP; + + while (assoc != NULL) + { + + if (pthread_mutex_lock (&(assoc->lock)) == 0) + { + pthread_key_t k; + if ((k = assoc->key) != NULL) + { + /* + * Key still active; pthread_key_delete + * will block on this same mutex before + * it can release actual key; therefore, + * key is valid and we can call the destroy + * routine; + */ + void *value = NULL; + + value = pthread_getspecific (k); + if (value != NULL && k->destructor != NULL) + { + + __try + { + /* + * Run the caller's cleanup routine. + */ + (*(k->destructor)) (value); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + /* + * A system unexpected exception had occurred + * running the user's destructor. + * We get control back within this block. + */ + } + } + } + + /* + * mark assoc->thread as NULL to indicate the + * thread no longer references this association + */ + assoc->thread = NULL; + + /* + * Remove association from the pthread_t chain + */ + *nextP = assoc->nextKey; + + pthread_mutex_unlock (&(assoc->lock)); + + _pthread_tkAssocDestroy (assoc); + + assoc = *nextP; + } + } + } + +} /* callUserDestroyRoutines */ + +/* */ + + +#if 0 /* Pre Bossom */ + /* Thread ID management. --------------------- @@ -141,3 +550,5 @@ _pthread_delete_thread(_pthread_t * thread) return EINVAL; } + +#endif /* Pre Bossom */ -- cgit v1.2.3