diff options
-rw-r--r-- | ChangeLog | 69 | ||||
-rw-r--r-- | attr.c | 354 | ||||
-rw-r--r-- | buildlib.bat | 3 | ||||
-rw-r--r-- | cleanup.c | 135 | ||||
-rw-r--r-- | create.c | 7 | ||||
-rw-r--r-- | dll.c | 4 | ||||
-rw-r--r-- | fork.c | 6 | ||||
-rw-r--r-- | implement.h | 101 | ||||
-rw-r--r-- | misc.c | 1 | ||||
-rw-r--r-- | private.c | 2 | ||||
-rw-r--r-- | pthread.def | 4 | ||||
-rw-r--r-- | pthread.h | 160 | ||||
-rw-r--r-- | sched.c | 20 | ||||
-rw-r--r-- | semaphore.c | 257 | ||||
-rw-r--r-- | semaphore.h | 65 | ||||
-rw-r--r-- | sync.c | 5 | ||||
-rw-r--r-- | tsd.c | 4 |
17 files changed, 1039 insertions, 158 deletions
@@ -1,3 +1,72 @@ +Tue Dec 29 13:11:16 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au> + + * implement.h: Move the following struct definitions to pthread.h: + pthread_t_, pthread_attr_t_, pthread_mutex_t_, pthread_mutex_t_, + pthread_mutexattr_t_, pthread_key_t_, pthread_cond_t_, + pthread_condattr_t_, pthread_once_t_. + + * pthread.h: Add "_" prefix to pthread_push_cleanup and + pthread_pop_cleanup internal routines, and associated struct and + typedefs. + + * buildlib.bat: Add compile command for semaphore.c + + * pthread.def: Comment out pthread_atfork routine name. + Now unimplemented. + + * tsd.c (pthread_setspecific): Rename tkAssocCreate to + _pthread_tkAssocCreate. + (pthread_key_delete): Rename tkAssocDestroy to + _pthread_tkAssocDestroy. + + * sync.c (pthread_join): Rename threadDestroy to _pthread_threadDestroy + + * sched.c (is_attr): attr is now **attr (was *attr), so add extra + NULL pointer test. + (pthread_attr_setschedparam): Increase redirection for attr which is + now a **. + (pthread_attr_getschedparam): Ditto. + (pthread_setschedparam): Change thread validation and rename "thread" + Win32 thread Handle element name to match John Bossom's version. + (pthread_getschedparam): Ditto. + + * private.c (_pthread_threadDestroy): Rename call to + callUserDestroyRoutines() as _pthread_callUserDestroyRoutines() + + * misc.c: Add #include "implement.h". + + * dll.c: Remove defined(KLUDGE) wrapped code. + + * fork.c: Remove redefinition of ENOMEM. + + * create.c (pthread_create): Rename threadStart and threadDestroy calls + to _pthread_threadStart and _pthread_threadDestroy. + + * implement.h: Rename "detachedstate" to "detachstate". + + * attr.c: Rename "detachedstate" to "detachstate". + +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. + (pthread_attr_getstacksize): Merge with John Bossom's version. + (pthread_attr_setstackaddr): Merge with John Bossom's version. + (pthread_attr_getstackaddr): Merge with John Bossom's version. + (pthread_attr_init): Merge with John Bossom's version. + (pthread_attr_destroy): Merge with John Bossom's version. + (pthread_attr_getdetachstate): Merge with John Bossom's version. + (pthread_attr_setdetachstate): Merge with John Bossom's version. + (is_attr): attr is now **attr (was *attr), so add extra NULL pointer + test. + + * implement.h (pthread_attr_t_): Add and rename elements in JEB's + version to correspond to original, so that it can be used with + original attr routines. + + * pthread.h: Add #endif at end which was truncated in merging. + Sun Dec 20 14:51:58 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au> * misc.c (pthreadCancelableWait): New function by John Bossom. Non-standard @@ -16,15 +16,57 @@ is_attr(const pthread_attr_t *attr) { /* Return 0 if the attr object is valid, non-zero otherwise. */ - return (attr == NULL || attr->valid != _PTHREAD_ATTR_VALID); + return (attr == NULL || + *attr == NULL || + (*attr)->valid != _PTHREAD_ATTR_VALID); } -#ifdef _POSIX_THREAD_ATTR_STACKSIZE int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function specifies the size of the stack on + * which threads created with 'attr' will run. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * stacksize + * stack size, in bytes. + * + * + * DESCRIPTION + * This function specifies the size of the stack on + * which threads created with 'attr' will run. + * + * NOTES: + * 1) Function supported only if this macro is + * defined: + * + * _POSIX_THREAD_ATTR_STACKSIZE + * + * 2) Find the default first (using + * pthread_attr_getstacksize), then increase + * by multiplying. + * + * 3) Only use if thread needs more than the + * default. + * + * RESULTS + * 0 successfully set stack size, + * EINVAL 'attr' is invalid or stacksize too + * small or too big. + * ENOSYS function not supported + * + * ------------------------------------------------------ + */ { +#ifdef _POSIX_THREAD_ATTR_STACKSIZE + /* Verify that the stack size is within range. */ if (stacksize < PTHREAD_STACK_MIN) { @@ -37,89 +79,295 @@ pthread_attr_setstacksize(pthread_attr_t *attr, } /* Everything is okay. */ - attr->stacksize = stacksize; + (*attr)->stacksize = stacksize; return 0; + +#else + + return ENOSYS; + +#endif /* _POSIX_THREAD_ATTR_STACKSIZE */ + } int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function determines the size of the stack on + * which threads created with 'attr' will run. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * stacksize + * pointer to size_t into which is returned the + * stack size, in bytes. + * + * + * DESCRIPTION + * This function determines the size of the stack on + * which threads created with 'attr' will run. + * + * NOTES: + * 1) Function supported only if this macro is + * defined: + * + * _POSIX_THREAD_ATTR_STACKSIZE + * + * 2) Use on newly created attributes object to + * find the default stack size. + * + * RESULTS + * 0 successfully retrieved stack size, + * EINVAL 'attr' is invalid + * ENOSYS function not supported + * + * ------------------------------------------------------ + */ { +#ifdef _POSIX_THREAD_ATTR_STACKSIZE + if (is_attr(attr) != 0) { return EINVAL; } /* Everything is okay. */ - *stacksize = attr->stacksize; + *stacksize = (*attr)->stacksize; return 0; -} + +#else + + return ENOSYS; #endif /* _POSIX_THREAD_ATTR_STACKSIZE */ -#ifdef _POSIX_THREAD_ATTR_STACKADDR +} + int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Threads created with 'attr' will run on the stack + * starting at 'stackaddr'. + * Stack must be at least PTHREAD_STACK_MIN bytes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * stacksize + * stack size, in bytes. + * + * + * DESCRIPTION + * Threads created with 'attr' will run on the stack + * starting at 'stackaddr'. + * Stack must be at least PTHREAD_STACK_MIN bytes. + * + * NOTES: + * 1) Function supported only if this macro is + * defined: + * + * _POSIX_THREAD_ATTR_STACKADDR + * + * 2) Create only one thread for each stack + * address.. + * + * 3) Ensure that stackaddr is aligned. + * + * RESULTS + * 0 successfully set stack address, + * EINVAL 'attr' is invalid + * ENOSYS function not supported + * + * ------------------------------------------------------ + */ { +#if defined( _POSIX_THREAD_ATTR_STACKADDR ) + if (is_attr(attr) != 0) { return EINVAL; } + + (*attr)->stackaddr = stackaddr; + return 0; + +#else + return ENOSYS; + +#endif /* _POSIX_THREAD_ATTR_STACKADDR */ } int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function determines the address of the stack + * on which threads created with 'attr' will run. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * stackaddr + * pointer into which is returned the stack address. + * + * + * DESCRIPTION + * This function determines the address of the stack + * on which threads created with 'attr' will run. + * + * NOTES: + * 1) Function supported only if this macro is + * defined: + * + * _POSIX_THREAD_ATTR_STACKADDR + * + * 2) Create only one thread for each stack + * address.. + * + * RESULTS + * 0 successfully retreived stack address, + * EINVAL 'attr' is invalid + * ENOSYS function not supported + * + * ------------------------------------------------------ + */ { +#if defined( _POSIX_THREAD_ATTR_STACKADDR ) + if (is_attr(attr) != 0) { return EINVAL; } + + *stackaddr = (*attr)->stackaddr; + return 0; + +#else + return ENOSYS; -} #endif /* _POSIX_THREAD_ATTR_STACKADDR */ +} int pthread_attr_init(pthread_attr_t *attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Initializes a thread attributes object with default + * attributes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * + * DESCRIPTION + * Initializes a thread attributes object with default + * attributes. + * + * NOTES: + * 1) Used to define thread attributes + * + * RESULTS + * 0 successfully initialized attr, + * ENOMEM insufficient memory for attr. + * + * ------------------------------------------------------ + */ { + pthread_attr_t attr_result; + int result = 0; + if (attr == NULL) { /* This is disallowed. */ return EINVAL; } + attr_result = malloc (sizeof (*attr_result)); + + if (attr_result == NULL) + { + return ENOMEM; + } + #ifdef _POSIX_THREAD_ATTR_STACKSIZE - attr->stacksize = PTHREAD_STACK_MIN; + attr_result->stacksize = PTHREAD_STACK_MIN; +#endif + +#ifdef _POSIX_THREAD_ATTR_STACKADDR + /* FIXME: Set this to something sensible when we support it. */ + attr_result->stackaddr = NULL; #endif - attr->detachedstate = PTHREAD_CREATE_JOINABLE; + attr_result->detachstate = PTHREAD_CREATE_JOINABLE; + #if HAVE_SIGSET_T - memset(&(attr->sigmask), 0, sizeof(sigset_t)); + memset(&(attr_result->sigmask), 0, sizeof(sigset_t)); #endif /* HAVE_SIGSET_T */ /* Priority uses Win32 priority values. */ - attr->priority = THREAD_PRIORITY_NORMAL; + attr_result->priority = THREAD_PRIORITY_NORMAL; - attr->valid = _PTHREAD_ATTR_VALID; + attr_result->valid = _PTHREAD_ATTR_VALID; + + *attr = attr_result; return 0; } int pthread_attr_destroy(pthread_attr_t *attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Destroys a thread attributes object. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * + * DESCRIPTION + * Destroys a thread attributes object. + * + * NOTES: + * 1) Does not affect threads created with 'attr'. + * + * RESULTS + * 0 successfully destroyed attr, + * EINVAL 'attr' is invalid. + * + * ------------------------------------------------------ + */ { if (is_attr(attr) != 0) { return EINVAL; } - /* Set the attribute object to a specific invalid value. */ - attr->valid = 0; + /* + * Set the attribute object to a specific invalid value. + */ + (*attr)->valid = 0; + free (*attr); + *attr = NULL; return 0; } @@ -127,19 +375,89 @@ pthread_attr_destroy(pthread_attr_t *attr) int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function determines whether threads created with + * 'attr' will run detached. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * detachstate + * pointer to an integer into which is returned one + * of: + * + * PTHREAD_CREATE_JOINABLE + * Thread ID is valid, must be joined + * + * PTHREAD_CREATE_DETACHED + * Thread ID is invalid, cannot be joined, + * canceled, or modified + * + * + * DESCRIPTION + * This function determines whether threads created with + * 'attr' will run detached. + * + * NOTES: + * 1) You cannot join or cancel detached threads. + * + * RESULTS + * 0 successfully retrieved detach state, + * EINVAL 'attr' is invalid + * + * ------------------------------------------------------ + */ { if (is_attr(attr) != 0 || detachstate == NULL) { + *detachstate = PTHREAD_CREATE_DETACHED; return EINVAL; } - *detachstate = attr->detachedstate; + *detachstate = (*attr)->detachstate; return 0; } int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function specifies whether threads created with + * 'attr' will run detached. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * detachstate + * an integer containing one of: + * + * PTHREAD_CREATE_JOINABLE + * Thread ID is valid, must be joined + * + * PTHREAD_CREATE_DETACHED + * Thread ID is invalid, cannot be joined, + * canceled, or modified + * + * + * DESCRIPTION + * This function specifies whether threads created with + * 'attr' will run detached. + * + * NOTES: + * 1) You cannot join or cancel detached threads. + * + * RESULTS + * 0 successfully set detach state, + * EINVAL 'attr' or 'detachstate' is invalid + * + * ------------------------------------------------------ + */ { if (is_attr(attr) != 0) { @@ -152,6 +470,10 @@ pthread_attr_setdetachstate(pthread_attr_t *attr, return EINVAL; } - attr->detachedstate = detachstate; + (*attr)->detachstate = detachstate; return 0; } + + + + diff --git a/buildlib.bat b/buildlib.bat index e8a674e..5e2e1c8 100644 --- a/buildlib.bat +++ b/buildlib.bat @@ -16,5 +16,8 @@ cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c sched. cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c signal.c cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c sync.c cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c tsd.c +cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c semaphore.c cl /LD /Zi *.obj /Fepthread.dll /link /nodefaultlib:libcmt /implib:pthread.lib msvcrt.lib /def:pthread.def + + @@ -12,6 +12,139 @@ #include "pthread.h" #include "implement.h" +/* + * Code contributed by John E. Bossom <JEB>. + */ + +_pthread_cleanup_t * +_pthread_pop_cleanup (int execute) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function pops the most recently pushed cleanup + * handler. If execute is nonzero, then the cleanup handler + * is executed if non-null. + * + * PARAMETERS + * execute + * if nonzero, execute the cleanup handler + * + * + * DESCRIPTION + * This function pops the most recently pushed cleanup + * handler. If execute is nonzero, then the cleanup handler + * is executed if non-null. + * NOTE: specify 'execute' as nonzero to avoid duplication + * of common cleanup code. + * + * RESULTS + * N/A + * + * ------------------------------------------------------ + */ +{ + _pthread_cleanup_t *cleanup; + + cleanup = pthread_getspecific (_pthread_cleanupKey); + + if (cleanup != NULL) + { + if (execute && (cleanup->routine != NULL)) + { + +#ifdef _WIN32 + + __try + { + /* + * Run the caller's cleanup routine. + */ + (*cleanup->routine) (cleanup->arg); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + /* + * A system unexpected exception had occurred + * running the user's cleanup routine. + * We get control back within this block. + */ + } + } + +#else + + /* + * Run the caller's cleanup routine. + */ + (*cleanup->routine) (cleanup->arg); + +#endif /* _WIN32 */ + + pthread_setspecific (_pthread_cleanupKey, cleanup->prev); + } + + return (cleanup); + +} /* _pthread_pop_cleanup */ + + +void +_pthread_push_cleanup (_pthread_cleanup_t * cleanup, + void (*routine) (void *), + void *arg) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function pushes a new cleanup handler onto the thread's stack + * of cleanup handlers. Each cleanup handler pushed onto the stack is + * popped and invoked with the argument 'arg' when + * a) the thread exits by calling 'pthread_exit', + * b) when the thread acts on a cancellation request, + * c) or when the thrad calls pthread_cleanup_pop with a nonzero + * 'execute' argument + * + * PARAMETERS + * cleanup + * a pointer to an instance of pthread_cleanup_t, + * + * routine + * pointer to a cleanup handler, + * + * arg + * parameter to be passed to the cleanup handler + * + * + * DESCRIPTION + * This function pushes a new cleanup handler onto the thread's stack + * of cleanup handlers. Each cleanup handler pushed onto the stack is + * popped and invoked with the argument 'arg' when + * a) the thread exits by calling 'pthread_exit', + * b) when the thread acts on a cancellation request, + * c) or when the thrad calls pthread_cleanup_pop with a nonzero + * 'execute' argument + * NOTE: pthread_push_cleanup, pthread_pop_cleanup must be paired + * in the same lexical scope. + * + * RESULTS + * pthread_cleanup_t * + * pointer to the previous cleanup + * + * ------------------------------------------------------ + */ +{ + cleanup->routine = routine; + cleanup->arg = arg; + cleanup->prev = pthread_getspecific (_pthread_cleanupKey); + + pthread_setspecific (_pthread_cleanupKey, (void *) cleanup); + +} /* _pthread_push_cleanup */ + +/* </JEB> */ + + +#if 0 /* Pre Bossom */ + int _pthread_handler_push(int stack, int poporder, @@ -214,3 +347,5 @@ _pthread_destructor_run_all() break; } } + +#endif /* Pre Bossom */ @@ -90,7 +90,6 @@ pthread_create (pthread_t * tid, { stackSize = (*attr)->stacksize; thread->detachState = (*attr)->detachstate; - } else { @@ -109,7 +108,7 @@ pthread_create (pthread_t * tid, _beginthreadex ( (void *) NULL, /* No security info */ (unsigned) stackSize, /* default stack size */ - (unsigned (__stdcall *) (void *)) threadStart, + (unsigned (__stdcall *) (void *)) _pthread_threadStart, parms, (unsigned) run ? 0 : CREATE_SUSPENDED, (unsigned *) &(thread->thread)); @@ -130,7 +129,7 @@ FAIL0: if (result != 0) { - threadDestroy (thread); + _pthread_threadDestroy (thread); thread = NULL; if (parms != NULL) @@ -235,7 +234,7 @@ pthread_create(pthread_t *thread, attr_copy->stacksize = PTHREAD_STACK_MIN; } - attr_copy->detachedstate = attr->detachedstate; + attr_copy->detachstate = attr->detachstate; attr_copy->priority = attr->priority; #if HAVE_SIGSET_T @@ -69,10 +69,6 @@ DllMain ( if (_pthread_processInitialized) { -#if defined( KLUDGE ) - _pthread_cleanupStack (); -#endif /* KLUDGE */ - self = (pthread_t) pthread_getspecific (_pthread_selfThreadKey); /* @@ -5,12 +5,12 @@ * Implementation of fork() for POSIX threads. */ -/* FIXME! */ -#define ENOMEM 0 #include "pthread.h" #include "implement.h" +#if 0 /* Pre Bossom */ + int pthread_atfork(void (*prepare)(void), void (*parent)(void), @@ -139,3 +139,5 @@ fork() } #endif /* HAVE_PID_T && HAVE_FORK */ + +#endif /* Pre Bossom */ diff --git a/implement.h b/implement.h index 523f475..c3be637 100644 --- a/implement.h +++ b/implement.h @@ -13,107 +13,6 @@ * Code contributed by John E. Bossom <JEB>. */ -typedef enum { - /* - * This enumeration represents the state of the thread; - * The thread is still "alive" if the numeric value of the - * state is greater or equal "PThreadStateRunning". - */ - PThreadStateInitial = 0, /* Thread not running */ - PThreadStateRunning, /* Thread alive & kicking */ - PThreadStateSuspended, /* Thread alive but suspended */ - PThreadStateCanceling, /* Thread alive but and is */ - /* in the process of terminating */ - /* due to a cancellation request */ - PThreadStateException, /* Thread alive but exiting */ - /* due to an exception */ - PThreadStateLast -} -PThreadState; - - -typedef enum { - /* - * This enumeration represents the reason why a thread has - * terminated/is terminating. - */ - PThreadDemisePeaceful = 0, /* Death due natural causes */ - PThreadDemiseCancelled, /* Death due to user cancel */ - PThreadDemiseException, /* Death due to unhandled */ - /* exception */ - PThreadDemiseNotDead /* I'm not dead! */ -} -PThreadDemise; - - -struct pthread_t_ { - DWORD thread; - HANDLE threadH; - PThreadState state; - PThreadDemise demise; - void *exitStatus; - void *parms; - int detachState; - int cancelState; - int cancelType; - HANDLE cancelEvent; - int implicit:1; - void *keys; -}; - - -struct pthread_attr_t_ { - void *stackaddr; - size_t stacksize; - int detachstate; -}; - - -struct pthread_key_t_ { - DWORD key; - void (*destructor) (void *); - pthread_mutex_t threadsLock; - void *threads; -}; - - -struct pthread_mutexattr_t_ { - int pshared; -}; - - -struct pthread_mutex_t_ { - int valid; - CRITICAL_SECTION cs; - }; - - -struct pthread_cond_t_ { - long waiters; /* # waiting threads */ - pthread_mutex_t waitersLock; /* Mutex that guards access to - waiter count */ - sem_t sema; /* Queue up threads waiting for the - condition to become signaled */ - HANDLE waitersDone; /* An auto reset event used by the - broadcast/signal thread to wait - for the waiting thread(s) to wake - up and get a chance at the - semaphore */ - int wasBroadcast; /* keeps track if we are signaling - or broadcasting */ -}; - - -struct pthread_condattr_t_ { - int pshared; -}; - - -struct pthread_once_t_ { - unsigned short flag; - pthread_mutex_t lock; -}; - typedef struct ThreadParms ThreadParms; typedef struct ThreadKeyAssoc ThreadKeyAssoc; @@ -8,6 +8,7 @@ #include <errno.h> #include "pthread.h" +#include "implement.h" int pthread_once(pthread_once_t *once_control, @@ -155,7 +155,7 @@ _pthread_threadDestroy (pthread_t thread) if (thread != NULL) { - callUserDestroyRoutines (thread); + _pthread_callUserDestroyRoutines (thread); if (thread->cancelEvent != NULL) { diff --git a/pthread.def b/pthread.def index 63687f5..df689cc 100644 --- a/pthread.def +++ b/pthread.def @@ -1,12 +1,12 @@ ; pthread.def -; Last updated: $Date: 1998/10/04 23:01:59 $ +; Last updated: $Date: 1998/12/28 23:01:11 $ ; Currently unimplemented functions are commented out. LIBRARY pthread EXPORTS -pthread_atfork +;pthread_atfork pthread_attr_destroy pthread_attr_getdetachstate ;pthread_attr_getinheritsched @@ -234,7 +234,7 @@ struct timespec { #include <semaphore.h> -#include <sched.h> +/* #include <sched.h> /**/ #ifdef __cplusplus @@ -397,7 +397,7 @@ extern "C" typedef struct pthread_t_ *pthread_t; - typedef struct pthread_attr_t_ pthread_attr_t; + typedef struct pthread_attr_t_ *pthread_attr_t; typedef struct pthread_once_t_ pthread_once_t; typedef struct pthread_key_t_ *pthread_key_t; typedef struct pthread_mutex_t_ pthread_mutex_t; @@ -483,6 +483,126 @@ extern "C" /* * ==================== * ==================== + * Opaque Structure Definitions + * ==================== + * ==================== + */ + +typedef enum { + /* + * This enumeration represents the state of the thread; + * The thread is still "alive" if the numeric value of the + * state is greater or equal "PThreadStateRunning". + */ + PThreadStateInitial = 0, /* Thread not running */ + PThreadStateRunning, /* Thread alive & kicking */ + PThreadStateSuspended, /* Thread alive but suspended */ + PThreadStateCanceling, /* Thread alive but and is */ + /* in the process of terminating */ + /* due to a cancellation request */ + PThreadStateException, /* Thread alive but exiting */ + /* due to an exception */ + PThreadStateLast +} +PThreadState; + + +typedef enum { + /* + * This enumeration represents the reason why a thread has + * terminated/is terminating. + */ + PThreadDemisePeaceful = 0, /* Death due natural causes */ + PThreadDemiseCancelled, /* Death due to user cancel */ + PThreadDemiseException, /* Death due to unhandled */ + /* exception */ + PThreadDemiseNotDead /* I'm not dead! */ +} +PThreadDemise; + + +struct pthread_t_ { + DWORD thread; + HANDLE threadH; + PThreadState state; + PThreadDemise demise; + void *exitStatus; + void *parms; + int detachState; + int cancelState; + int cancelType; + HANDLE cancelEvent; + int implicit:1; + void *keys; +}; + + +/* + * Special value to mark attribute objects as valid. + */ +#define _PTHREAD_ATTR_VALID 0xC4C0FFEE + +struct pthread_attr_t_ { + long valid; + void *stackaddr; + size_t stacksize; + int detachstate; + int priority; +#if HAVE_SIGSET_T + sigset_t sigmask; +#endif /* HAVE_SIGSET_T */ +}; + + +struct pthread_mutex_t_ { + int valid; + CRITICAL_SECTION cs; + }; + + +struct pthread_mutexattr_t_ { + int pshared; +}; + + +struct pthread_key_t_ { + DWORD key; + void (*destructor) (void *); + pthread_mutex_t threadsLock; + void *threads; +}; + + +struct pthread_cond_t_ { + long waiters; /* # waiting threads */ + pthread_mutex_t waitersLock; /* Mutex that guards access to + waiter count */ + sem_t sema; /* Queue up threads waiting for the + condition to become signaled */ + HANDLE waitersDone; /* An auto reset event used by the + broadcast/signal thread to wait + for the waiting thread(s) to wake + up and get a chance at the + semaphore */ + int wasBroadcast; /* keeps track if we are signaling + or broadcasting */ +}; + + +struct pthread_condattr_t_ { + int pshared; +}; + + +struct pthread_once_t_ { + unsigned short flag; + pthread_mutex_t lock; +}; + + +/* + * ==================== + * ==================== * Scheduling * ==================== * ==================== @@ -510,28 +630,31 @@ extern "C" * WIN32 SEH or C++ */ -#ifndef __cplusplus + typedef struct _pthread_cleanup_t _pthread_cleanup_t; -/* - * C implementation of PThreads cancel cleanup - */ - typedef struct pthread_cleanup_t pthread_cleanup_t; - - struct pthread_cleanup_t + struct _pthread_cleanup_t { void (*routine) (void *); void *arg; - pthread_cleanup_t *prev; +#if !defined(__cplusplus) + _pthread_cleanup_t *prev; +#endif }; +#ifndef __cplusplus + +/* + * C implementation of PThreads cancel cleanup + */ + #define pthread_cleanup_push( _rout, _arg ) \ { \ - pthread_cleanup_t cleanup; \ + _pthread_cleanup_t _cleanup; \ \ - pthread_push_cleanup( &cleanup, (_rout), (_arg) ); \ + _pthread_push_cleanup( &_cleanup, (_rout), (_arg) ); \ #define pthread_cleanup_pop( _execute ) \ - (void) pthread_pop_cleanup( _execute ); \ + (void) _pthread_pop_cleanup( _execute ); \ } #else /* !__cplusplus */ @@ -543,7 +666,7 @@ extern "C" #define pthread_cleanup_push( _rout, _arg ) \ { \ - pthread_cleanup_t _cleanup; \ + _pthread_cleanup_t _cleanup; \ \ _cleanup.routine = (_rout); \ _cleanup.arg = (_arg); \ @@ -571,7 +694,7 @@ extern "C" #define pthread_cleanup_push( _rout, _arg ) \ { \ - pthread_cleanup_t _cleanup; \ + _pthread_cleanup_t _cleanup; \ \ _cleanup.routine = (_rout); \ _cleanup.arg = (_arg); \ @@ -652,11 +775,13 @@ pthread_t pthread_self (void); int pthread_cancel (pthread_t thread); -pthread_cleanup_t *pthread_pop_cleanup (int execute); +#ifndef __cplusplus +_pthread_cleanup_t *_pthread_pop_cleanup (int execute); -void pthread_push_cleanup (pthread_cleanup_t * cleanup, +void _pthread_push_cleanup (_pthread_cleanup_t * cleanup, void (*routine) (void *), void *arg); +#endif /* !__cplusplus */ int pthread_setcancelstate (int state, int *oldstate); @@ -817,3 +942,4 @@ int pthreadCancelableWait (HANDLE waitHandle); } /* End of extern "C" */ #endif /* __cplusplus */ +#endif /* PTHREAD_H */ @@ -15,7 +15,9 @@ static int is_attr(const pthread_attr_t *attr) { - return (attr == NULL || attr->valid != _PTHREAD_ATTR_VALID) ? 1 : 0; + return (attr == NULL || + *attr == NULL || + (*attr)->valid != _PTHREAD_ATTR_VALID) ? 1 : 0; } int @@ -27,11 +29,12 @@ pthread_attr_setschedparam(pthread_attr_t *attr, return EINVAL; } - attr->priority = param->sched_priority; + (*attr)->priority = param->sched_priority; return 0; } -int pthread_attr_getschedparam(const pthread_attr_t *attr, +int +pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param) { if (is_attr(attr) != 0 || param == NULL) @@ -39,7 +42,7 @@ int pthread_attr_getschedparam(const pthread_attr_t *attr, return EINVAL; } - param->sched_priority = attr->priority; + param->sched_priority = (*attr)->priority; return 0; } @@ -47,7 +50,7 @@ int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param) { /* Validate the thread id. */ - if (_PTHREAD_VALID(thread) < 0) + if (thread == NULL || thread->threadH == 0) { return EINVAL; } @@ -72,7 +75,8 @@ int pthread_setschedparam(pthread_t thread, int policy, } /* This is practically guaranteed to return TRUE. */ - (void) SetThreadPriority(thread->win32handle, param->sched_priority); + (void) SetThreadPriority(thread->threadH, param->sched_priority); + return 0; } @@ -82,7 +86,7 @@ int pthread_getschedparam(pthread_t thread, int *policy, int prio; /* Validate the thread id. */ - if (_PTHREAD_VALID(thread) != 0) + if (thread == NULL || thread->threadH == 0) { return EINVAL; } @@ -97,7 +101,7 @@ int pthread_getschedparam(pthread_t thread, int *policy, *policy = SCHED_OTHER; /* Fill out the sched_param structure. */ - prio = GetThreadPriority(thread->win32handle); + prio = GetThreadPriority(thread->threadH); if (prio == THREAD_PRIORITY_ERROR_RETURN) { return EINVAL; diff --git a/semaphore.c b/semaphore.c new file mode 100644 index 0000000..04e99f5 --- /dev/null +++ b/semaphore.c @@ -0,0 +1,257 @@ +/* + * ------------------------------------------------------------- + * + * $Header: /cvs/pthreads-win32/pthreads/semaphore.c,v 1.1.2.1 1998/12/28 23:01:14 rpj Exp $ + * + * Module: semaphore.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * They are supposed to follow the older UNIX convention for + * reporting errors. That is, on failure they are supposed + * to return a value of -1 and store the appropriate error + * number into 'errno'. + * HOWEVER,errno cannot be modified in a multithreaded + * program on WIN32; therefore, the value is returned as + * the function value. + * It is recommended that you compare for zero (0) for success + * instead of -1 for failure when checking the status of + * these functions. + * + * Contents: + * Public Methods Author + * -------------- ------ + * sem_init John E. Bossom Mar 1998 + * sem_destroy John E. Bossom Mar 1998 + * sem_trywait John E. Bossom Mar 1998 + * sem_wait John E. Bossom Mar 1998 + * sem_post John E. Bossom Mar 1998 + * + * Private Methods + * --------------- + * + * ------------------------------------------------------------- + */ +#include <pthread.h> +#include <windows.h> +#include <process.h> +#include <errno.h> +#include <string.h> + +#include "semaphore.h" + + + +int +sem_init (sem_t * sem, int pshared, unsigned int value) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function initializes an unnamed semaphore. the + * initial value of the semaphore is 'value' + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * pshared + * if zero, this semaphore may only be shared between + * threads in the same process. + * if nonzero, the semaphore can be shared between + * processes + * + * value + * initial value of the semaphore counter + * + * DESCRIPTION + * This function initializes an unnamed semaphore. The + * initial value of the semaphore is set to 'value'. + * + * RESULTS + * 0 successfully created semaphore, + * EINVAL 'sem' is not a valid semaphore, + * ENOSPC a required resource has been exhausted, + * ENOSYS semaphores are not supported, + * EPERM the process lacks appropriate privilege + * + * ------------------------------------------------------ + */ +{ + int result = 0; + + if (pshared != 0) + { + /* + * Creating a semaphore that can be shared between + * processes + */ + result = EPERM; + + } + else + { + /* + * NOTE: Taking advantage of the fact that + * sem_t is a simple structure with one entry; + * We don't have to allocate it... + */ + *sem = CreateSemaphore ( + 0, + value, + 0x7FFFFFF, + NULL); + + if (*sem == 0) + { + result = ENOSPC; + } + } + + return (result); + +} /* sem_init */ + + +int +sem_destroy (sem_t * sem) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function destroys an unnamed semaphore. + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * DESCRIPTION + * This function destroys an unnamed semaphore. + * + * RESULTS + * 0 successfully destroyed semaphore, + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * EBUSY threads (or processes) are currently + * blocked on 'sem' + * + * ------------------------------------------------------ + */ +{ + return ((sem == NULL) + ? EINVAL + : (CloseHandle (*sem) + ? 0 + : EINVAL)); + +} /* sem_destroy */ + + +int +sem_trywait (sem_t * sem) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function tries to wait on a semaphore. + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * DESCRIPTION + * This function tries to wait on a semaphore. If the + * semaphore value is greater than zero, it decreases + * its value by one. If the semaphore value is zero, then + * this function returns immediately with the error EAGAIN + * + * RESULTS + * 0 successfully destroyed semaphore, + * EAGAIN the semaphore was already locked, + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * EINTR the function was interrupted by a signal, + * EDEADLK a deadlock condition was detected. + * + * ------------------------------------------------------ + */ +{ + return ((sem == NULL) + ? EINVAL + : ((WaitForSingleObject (*sem, 0) == WAIT_TIMEOUT) + ? EAGAIN + : 0)); + +} /* sem_trywait */ + + +int +sem_wait (sem_t * sem) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function waits on a semaphore. + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * DESCRIPTION + * This function waits on a semaphore. If the + * semaphore value is greater than zero, it decreases + * its value by one. If the semaphore value is zero, then + * the calling thread (or process) is blocked until it can + * successfully decrease the value or until interrupted by + * a signal. + * + * RESULTS + * 0 successfully destroyed semaphore, + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * EINTR the function was interrupted by a signal, + * EDEADLK a deadlock condition was detected. + * + * ------------------------------------------------------ + */ +{ + + return ((sem == NULL) + ? EINVAL + : pthreadCancelableWait (*sem) + ); + +} /* sem_wait */ + + +int +sem_post (sem_t * sem) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function posts a wakeup to a semaphore. + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * DESCRIPTION + * This function posts a wakeup to a semaphore. If there + * are waiting threads (or processes), on is awakened; + * otherwise, the semaphore value is incremented by one. + * + * RESULTS + * 0 successfully destroyed semaphore, + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * + * ------------------------------------------------------ + */ +{ + return ((sem == NULL) + ? EINVAL + : (ReleaseSemaphore (*sem, 1, 0) + ? 0 + : EINVAL)); + +} /* sem_post */ diff --git a/semaphore.h b/semaphore.h new file mode 100644 index 0000000..7b9d352 --- /dev/null +++ b/semaphore.h @@ -0,0 +1,65 @@ +/* + * ------------------------------------------------------------- + * + * $Header: /cvs/pthreads-win32/pthreads/semaphore.h,v 1.1.2.1 1998/12/28 23:01:15 rpj Exp $ + * + * Module: semaphore.h + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * They are supposed to follow the older UNIX convention for + * reporting errors. That is, on failure they are supposed + * to return a value of -1 and store the appropriate error + * number into 'errno'. + * HOWEVER,errno cannot be modified in a multithreaded + * program on WIN32; therefore, the value is returned as + * the function value. + * It is recommended that you compare for zero (0) for success + * 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 ) +#define SEMAPHORE_H + +#include <process.h> +#include <errno.h> + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +typedef HANDLE sem_t; + +int sem_init (sem_t * sem, int pshared, unsigned int value); + +int sem_destroy (sem_t * sem); + +int sem_trywait (sem_t * sem); + +int sem_wait (sem_t * sem); + +int sem_post (sem_t * sem); + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#endif /* !SEMAPHORE_H */ @@ -10,6 +10,9 @@ * Code contributed by John E. Bossom <JEB>. */ +#include "pthread.h" +#include "implement.h" + int pthread_detach (pthread_t tid) /* @@ -112,7 +115,7 @@ pthread_join (pthread_t thread, void **value_ptr) } else { - threadDestroy (thread); + _pthread_threadDestroy (thread); } } @@ -189,7 +189,7 @@ pthread_key_delete (pthread_key_t key) pthread_mutex_unlock (&(assoc->lock)); - tkAssocDestroy (assoc); + _pthread_tkAssocDestroy (assoc); assoc = next; } @@ -304,7 +304,7 @@ pthread_setspecific (pthread_key_t key, const void *value) * create an association if not found */ result = (assoc == NULL) - ? tkAssocCreate (&assoc, self, key) + ? _pthread_tkAssocCreate (&assoc, self, key) : 0; } else |