diff options
-rw-r--r-- | condvar.c | 231 | ||||
-rw-r--r-- | config.h | 13 | ||||
-rw-r--r-- | config.h.in | 16 | ||||
-rw-r--r-- | errno.c | 4 | ||||
-rw-r--r-- | implement.h | 62 | ||||
-rw-r--r-- | misc.c | 24 | ||||
-rw-r--r-- | mutex.c | 60 | ||||
-rw-r--r-- | private.c | 225 | ||||
-rw-r--r-- | pthread.def | 212 | ||||
-rw-r--r-- | pthread.h | 86 | ||||
-rw-r--r-- | sched.h | 4 | ||||
-rw-r--r-- | semaphore.c | 126 | ||||
-rw-r--r-- | semaphore.h | 13 | ||||
-rw-r--r-- | signal.c | 3 | ||||
-rw-r--r-- | tsd.c | 5 |
15 files changed, 551 insertions, 533 deletions
@@ -65,15 +65,6 @@ _cond_check_need_init(pthread_cond_t *cond) { result = pthread_cond_init(cond, NULL); } - else if (*cond == NULL) - { - /* - * The cv has been destroyed while we were waiting to - * initialise it, so the operation that caused the - * auto-initialisation should fail. - */ - result = EINVAL; - } LeaveCriticalSection(&_pthread_cond_test_init_lock); @@ -464,126 +455,27 @@ pthread_cond_destroy (pthread_cond_t * cond) return EINVAL; } - if (*cond != (pthread_cond_t) _PTHREAD_OBJECT_AUTO_INIT) - { - cv = *cond; - - if (pthread_mutex_lock(&(cv->waitersLock)) != 0) - { - return EINVAL; - } + cv = *cond; + if (cv != (pthread_cond_t) _PTHREAD_OBJECT_AUTO_INIT) + { if (cv->waiters > 0) { - (void) pthread_mutex_unlock(&(cv->waitersLock)); return EBUSY; } (void) sem_destroy (&(cv->sema)); - (void) CloseHandle (cv->waitersDone); - (void) pthread_mutex_unlock(&(cv->waitersLock)); (void) pthread_mutex_destroy (&(cv->waitersLock)); + (void) CloseHandle (cv->waitersDone); free(cv); - *cond = NULL; } - else - { - /* - * See notes in _cond_check_need_init() above also. - */ - EnterCriticalSection(&_pthread_cond_test_init_lock); - /* - * Check again. - */ - if (*cond == (pthread_cond_t) _PTHREAD_OBJECT_AUTO_INIT) - { - /* - * This is all we need to do to destroy a statically - * initialised cond that has not yet been used (initialised). - * If we get to here, another thread - * waiting to initialise this cond will get an EINVAL. - */ - *cond = NULL; - } - else - { - /* - * The cv has been initialised while we were waiting - * so assume it's in use. - */ - result = EBUSY; - } - - LeaveCriticalSection(&_pthread_cond_test_init_lock); - } + *cond = NULL; return (result); } -/* - * Arguments for cond_wait_cleanup, since we can only pass a - * single void * to it. - */ -typedef struct { - pthread_mutex_t * mutexPtr; - pthread_cond_t cv; - int * resultPtr; -} cond_wait_cleanup_args_t; - -static void -cond_wait_cleanup(void * args) -{ - cond_wait_cleanup_args_t * cleanup_args = (cond_wait_cleanup_args_t *) args; - pthread_mutex_t * mutexPtr = cleanup_args->mutexPtr; - pthread_cond_t cv = cleanup_args->cv; - int * resultPtr = cleanup_args->resultPtr; - int lock_result; - int lastWaiter; - - if ((lock_result = pthread_mutex_lock (&(cv->waitersLock))) == 0) - { - /* - * The waiter is responsible for decrementing - * its count, protected by an internal mutex. - */ - - cv->waiters--; - - lastWaiter = cv->wasBroadcast && (cv->waiters == 0); - - if (lastWaiter) - { - cv->wasBroadcast = FALSE; - } - - lock_result = pthread_mutex_unlock (&(cv->waitersLock)); - } - - if ((*resultPtr == 0 || *resultPtr == ETIMEDOUT) && lock_result == 0) - { - if (lastWaiter) - { - /* - * If we are the last waiter on this broadcast - * let the thread doing the broadcast proceed - */ - if (!SetEvent (cv->waitersDone)) - { - *resultPtr = EINVAL; - } - } - } - - /* - * We must always regain the external mutex, even when - * errors occur, because that's the guarantee that we give - * to our callers - */ - (void) pthread_mutex_lock (mutexPtr); -} - static int cond_timedwait (pthread_cond_t * cond, pthread_mutex_t * mutex, @@ -593,7 +485,6 @@ cond_timedwait (pthread_cond_t * cond, int internal_result = 0; int lastWaiter = FALSE; pthread_cond_t cv; - cond_wait_cleanup_args_t cleanup_args; if (cond == NULL || *cond == NULL) { @@ -619,22 +510,10 @@ cond_timedwait (pthread_cond_t * cond, cv = *cond; /* - * It's not OK to increment cond->waiters while the caller locked 'mutex', - * there may be other threads just waking up (with 'mutex' unlocked) - * and cv->... data is not protected. + * OK to increment cond->waiters because the caller locked 'mutex' */ - if (pthread_mutex_lock(&(cv->waitersLock)) != 0) - { - return EINVAL; - } - cv->waiters++; - if (pthread_mutex_unlock(&(cv->waitersLock)) != 0) - { - return EINVAL; - } - /* * We keep the lock held just long enough to increment the count of * waiters by one (above). @@ -642,41 +521,67 @@ cond_timedwait (pthread_cond_t * cond, * call to sem_wait since that will deadlock other calls * to pthread_cond_signal */ - cleanup_args.mutexPtr = mutex; - cleanup_args.cv = cv; - cleanup_args.resultPtr = &result; - - pthread_cleanup_push (cond_wait_cleanup, (void *) &cleanup_args); - if ((result = pthread_mutex_unlock (mutex)) == 0) { /* * Wait to be awakened by * pthread_cond_signal, or * pthread_cond_broadcast - * timeout * * Note: - * _pthread_sem_timedwait is a cancelation point, + * _pthread_sem_timedwait is a cancellation point, * hence providing the - * mechanism for making pthread_cond_wait a cancelation + * mechanism for making pthread_cond_wait a cancellation * point. We use the cleanup mechanism to ensure we - * re-lock the mutex and decrement the waiters count - * if we are canceled. + * re-lock the mutex if we are cancelled. */ + pthread_cleanup_push (pthread_mutex_lock, mutex); + if (_pthread_sem_timedwait (&(cv->sema), abstime) == -1) { result = errno; } + + pthread_cleanup_pop (0); } - pthread_cleanup_pop (1); + if ((internal_result = pthread_mutex_lock (&(cv->waitersLock))) == 0) + { + /* + * By making the waiter responsible for decrementing + * its count we don't have to worry about having an internal + * mutex. + */ + cv->waiters--; + + lastWaiter = cv->wasBroadcast && (cv->waiters == 0); + + internal_result = pthread_mutex_unlock (&(cv->waitersLock)); + } + + if (result == 0 && internal_result == 0) + { + if (lastWaiter) + { + /* + * If we are the last waiter on this broadcast + * let the thread doing the broadcast proceed + */ + if (!SetEvent (cv->waitersDone)) + { + result = EINVAL; + } + } + } /* - * "result" can be modified by the cleanup handler. - * Specifically, if we are the last waiting thread and failed - * to notify the broadcast thread to proceed. + * We must always regain the external mutex, even when + * errors occur because that's the guarantee that we give + * to our callers */ + (void) pthread_mutex_lock (mutex); + + return (result); } /* cond_timedwait */ @@ -855,7 +760,6 @@ pthread_cond_signal (pthread_cond_t * cond) /* * No-op if the CV is static and hasn't been initialised yet. - * Assuming that race conditions are harmless. */ if (cv == (pthread_cond_t) _PTHREAD_OBJECT_AUTO_INIT) { @@ -864,7 +768,6 @@ pthread_cond_signal (pthread_cond_t * cond) /* * If there aren't any waiters, then this is a no-op. - * Assuming that race conditions are harmless. */ if (cv->waiters > 0) { @@ -914,7 +817,6 @@ pthread_cond_broadcast (pthread_cond_t * cond) */ { int result = 0; - int wereWaiters = FALSE; pthread_cond_t cv; if (cond == NULL || *cond == NULL) @@ -926,41 +828,40 @@ pthread_cond_broadcast (pthread_cond_t * cond) /* * No-op if the CV is static and hasn't been initialised yet. - * Assuming that any race condition is harmless. */ if (cv == (pthread_cond_t) _PTHREAD_OBJECT_AUTO_INIT) { return 0; } - if (pthread_mutex_lock(&(cv->waitersLock)) == EINVAL) - { - return EINVAL; - } - cv->wasBroadcast = TRUE; - wereWaiters = (cv->waiters > 0); - if (wereWaiters) - { - /* - * Wake up all waiters - */ - result = (ReleaseSemaphore( cv->sema, cv->waiters, NULL ) - ? 0 - : EINVAL ); - } + /* + * Wake up all waiters + */ + +#ifdef NEED_SEM + + result = (_pthread_increase_semaphore( &cv->sema, cv->waiters ) + ? 0 + : EINVAL); + +#else /* NEED_SEM */ + + result = (ReleaseSemaphore( cv->sema, cv->waiters, NULL ) + ? 0 + : EINVAL); - (void) pthread_mutex_unlock(&(cv->waitersLock)); +#endif /* NEED_SEM */ - if (wereWaiters && result == 0) + if (cv->waiters > 0 && result == 0) { /* * Wait for all the awakened threads to acquire their part of * the counting semaphore */ - if (WaitForSingleObject (cv->waitersDone, INFINITE) - == WAIT_OBJECT_0) + if (WaitForSingleObject (cv->waitersDone, INFINITE) == + WAIT_OBJECT_0) { result = 0; } @@ -9,5 +9,14 @@ /* Define if you have the <signal.h> header file. */ #undef HAVE_SIGNAL_H -/* Define if you have the <windows.h> header file. */ -#undef HAVE_WINDOWS_H +/* Define if you don't have errno. (eg. WinCE) */ +#undef NEED_ERRNO + +/* Define if you don't have calloc. (eg. WinCE) */ +#undef NEED_CALLOC + +/* Define if you don't have ftime. (eg. WinCE) */ +#undef NEED_FTIME + +/* Define if you don't have semaphores. (eg. WinCE) */ +#undef NEED_SEM diff --git a/config.h.in b/config.h.in index 6671c7f..82805c1 100644 --- a/config.h.in +++ b/config.h.in @@ -3,8 +3,20 @@ /* Do we know about the C type sigset_t? */ #undef HAVE_SIGSET_T +/* Do we have the `_stdcall' keyword? */ +#undef STDCALL + /* Define if you have the <signal.h> header file. */ #undef HAVE_SIGNAL_H -/* Define if you have the <windows.h> header file. */ -#undef HAVE_WINDOWS_H +/* Define if you don't have errno. (eg. WinCE) */ +#undef NEED_ERRNO + +/* Define if you don't have calloc. (eg. WinCE) */ +#undef NEED_CALLOC + +/* Define if you don't have ftime. (eg. WinCE) */ +#undef NEED_FTIME + +/* Define if you don't have semaphores. (eg. WinCE) */ +#undef NEED_SEM @@ -24,7 +24,7 @@ * MA 02111-1307, USA */ -#if ! defined( _REENTRANT ) && ! defined( _MT ) +#if (! defined(HAVE_ERRNO)) || (! defined( _REENTRANT ) && ! defined( _MT )) #include "pthread.h" #include "implement.h" @@ -79,4 +79,4 @@ int * _errno( void ) } /* _errno */ -#endif /* !_REENTRANT && !_MT */ +#endif /* (! HAVE_ERRNO) || (!_REENTRANT && !_MT) */ diff --git a/implement.h b/implement.h index 70836dc..71ebf05 100644 --- a/implement.h +++ b/implement.h @@ -27,9 +27,8 @@ #ifndef _IMPLEMENT_H #define _IMPLEMENT_H -#define PT_STDCALL __stdcall - -#include <semaphore.h> +/* changed include from <semaphore.h> to use local file during development */ +#include "semaphore.h" typedef enum { /* @@ -161,22 +160,6 @@ struct pthread_condattr_t_ { int pshared; }; -#define RW_MAGIC 0x19283746 - -struct pthread_rwlock_t_ { - pthread_mutex_t rw_lock; /* basic lock on this struct */ - pthread_cond_t rw_condreaders; /* for reader threads waiting */ - pthread_cond_t rw_condwriters; /* for writer threads waiting */ - int rw_magic; /* for error checking */ - int rw_nwaitreaders; /* the number waiting */ - int rw_nwaitwriters; /* the number waiting */ - int rw_refcount; /* -1 if writer has the lock, - else # readers holding the lock */ -}; - -struct pthread_rwlockattr_t_ { - int pshared; -}; struct ThreadKeyAssoc { /* @@ -274,27 +257,18 @@ struct ThreadKeyAssoc { */ #define EXCEPTION_PTHREAD_SERVICES \ MAKE_SOFTWARE_EXCEPTION( SE_ERROR, \ - _PTHREAD_SERVICES_FACILITY, \ - _PTHREAD_SERVICES_ERROR ) + PTHREAD_SERVICES_FACILITY, \ + PTHREAD_SERVICES_ERROR ) -#define _PTHREAD_SERVICES_FACILITY 0xBAD -#define _PTHREAD_SERVICES_ERROR 0xDEED -/* - * Services available through EXCEPTION_PTHREAD_SERVICES - */ -#define _PTHREAD_EPS_CANCEL 0 -#define _PTHREAD_EPS_EXIT 1 +#define PTHREAD_SERVICES_FACILITY 0xBAD +#define PTHREAD_SERVICES_ERROR 0xDEED #else #ifdef __cplusplus -/* - * Exceptions similar to the SEH exceptions above. - */ -class Pthread_exception_cancel {}; -class Pthread_exception_exit {}; +class Pthread_exception {}; #else /* __cplusplus */ @@ -313,7 +287,12 @@ extern pthread_key_t _pthread_selfThreadKey; extern pthread_key_t _pthread_cleanupKey; extern CRITICAL_SECTION _pthread_mutex_test_init_lock; extern CRITICAL_SECTION _pthread_cond_test_init_lock; -extern CRITICAL_SECTION _pthread_rwlock_test_init_lock; + +/* Declared in misc.c */ +#ifdef NEED_CALLOC +#define calloc(n, s) _pthread_calloc(n, s) +void *_pthread_calloc(size_t n, size_t s); +#endif #ifdef __cplusplus @@ -335,12 +314,7 @@ void _pthread_threadDestroy (pthread_t tid); void _pthread_cleanupStack (void); -#if ! defined (__MINGW32__) || defined (__MSVCRT__) -unsigned PT_STDCALL -#else -void -#endif -_pthread_threadStart (ThreadParms * threadParms); +void *_pthread_threadStart (ThreadParms * threadParms); void _pthread_callUserDestroyRoutines (pthread_t thread); @@ -353,6 +327,12 @@ void _pthread_tkAssocDestroy (ThreadKeyAssoc * assoc); int _pthread_sem_timedwait (sem_t * sem, const struct timespec * abstime); +#ifdef NEED_SEM +void _pthread_decrease_semaphore(sem_t * sem); +BOOL _pthread_increase_semaphore(sem_t * sem, + unsigned int n); +#endif /* NEED_SEM */ + #ifdef __cplusplus } #endif /* __cplusplus */ @@ -365,7 +345,7 @@ int _pthread_sem_timedwait (sem_t * sem, * * Patch by Anders Norlander <anorland@hem2.passagen.se> */ -#if defined(__CYGWIN32__) || defined(__CYGWIN__) +#if defined(__CYGWIN32__) || defined(__CYGWIN__) || defined(_PTHREAD_CREATETHREAD) /* * Macro uses args so we can cast start_proc to LPTHREAD_START_ROUTINE @@ -163,6 +163,10 @@ pthread_self (void) self->thread = GetCurrentThreadId (); +#ifdef UNDER_CE + /* DuplicateHandle does not exist on WinCE */ + self->threadH = GetCurrentThread(); +#else if( !DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), @@ -175,6 +179,7 @@ pthread_self (void) free( self ); return (NULL); } +#endif } pthread_setspecific (_pthread_selfThreadKey, self); @@ -314,7 +319,7 @@ CancelableWait (HANDLE waitHandle, DWORD timeout) DWORD exceptionInformation[3]; - exceptionInformation[0] = (DWORD) (_PTHREAD_EPS_CANCEL); + exceptionInformation[0] = (DWORD) (0); exceptionInformation[1] = (DWORD) (0); exceptionInformation[2] = (DWORD) (0); @@ -328,7 +333,7 @@ CancelableWait (HANDLE waitHandle, DWORD timeout) #ifdef __cplusplus - throw Pthread_exception_cancel(); + throw Pthread_exception(); #endif /* __cplusplus */ @@ -361,4 +366,17 @@ pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout) return (CancelableWait(waitHandle, timeout)); } - +#ifdef NEED_CALLOC +void +*_pthread_calloc(size_t n, size_t s) { + unsigned int m = n*s; + void *p; + + p = malloc(m); + if (p == NULL) return NULL; + + memset(p, 0, m); + + return p; +} +#endif @@ -22,8 +22,9 @@ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA */ - -#include <errno.h> +
+/* errno.h or a replacement file is included by pthread.h */ +//#include <errno.h> #include "pthread.h" #include "implement.h" @@ -69,15 +70,6 @@ _mutex_check_need_init(pthread_mutex_t *mutex) { result = pthread_mutex_init(mutex, NULL); } - else if (*mutex == NULL) - { - /* - * The mutex has been destroyed while we were waiting to - * initialise it, so the operation that caused the - * auto-initialisation should fail. - */ - result = EINVAL; - } LeaveCriticalSection(&_pthread_mutex_test_init_lock); @@ -186,13 +178,13 @@ pthread_mutex_destroy(pthread_mutex_t *mutex) return EINVAL; } + mx = *mutex; + /* * Check to see if we have something to delete. */ - if (*mutex != (pthread_mutex_t) _PTHREAD_OBJECT_AUTO_INIT) + if (mx != (pthread_mutex_t) _PTHREAD_OBJECT_AUTO_INIT) { - mx = *mutex; - if (mx->mutex == 0) { DeleteCriticalSection(&mx->cs); @@ -201,44 +193,12 @@ pthread_mutex_destroy(pthread_mutex_t *mutex) { result = (CloseHandle (mx->mutex) ? 0 : EINVAL); } - - if (result == 0) - { - mx->mutex = 0; - free(mx); - *mutex = NULL; - } } - else - { - /* - * See notes in _mutex_check_need_init() above also. - */ - EnterCriticalSection(&_pthread_mutex_test_init_lock); - /* - * Check again. - */ - if (*mutex == (pthread_mutex_t) _PTHREAD_OBJECT_AUTO_INIT) - { - /* - * This is all we need to do to destroy a statically - * initialised mutex that has not yet been used (initialised). - * If we get to here, another thread - * waiting to initialise this mutex will get an EINVAL. - */ - *mutex = NULL; - } - else - { - /* - * The mutex has been initialised while we were waiting - * so assume it's in use. - */ - result = EBUSY; - } - - LeaveCriticalSection(&_pthread_mutex_test_init_lock); + if (result == 0) + { + mx->mutex = 0; + *mutex = NULL; } return(result); @@ -30,7 +30,7 @@ #endif /* !_MSC_VER && !__cplusplus && __GNUC__ */ -#include <sys/timeb.h> +//#include <sys/timeb.h> #include "pthread.h" #include "semaphore.h" #include "implement.h" @@ -60,6 +60,17 @@ _pthread_processInitialize (void) * ------------------------------------------------------ */ { + if (_pthread_processInitialized) { + /* + * ignore if already initialized. this is useful for + * programs that uses a non-dll pthread + * library. such programs must call _pthread_processInitialize() explicitely, + * since this initialization routine is automatically called only when + * the dll is loaded. + */ + return TRUE; + } + _pthread_processInitialized = TRUE; /* @@ -77,7 +88,6 @@ _pthread_processInitialize (void) */ InitializeCriticalSection(&_pthread_mutex_test_init_lock); InitializeCriticalSection(&_pthread_cond_test_init_lock); - InitializeCriticalSection(&_pthread_rwlock_test_init_lock); return (_pthread_processInitialized); @@ -132,66 +142,30 @@ _pthread_processTerminate (void) /* * Destroy the global test and init check locks. */ - DeleteCriticalSection(&_pthread_rwlock_test_init_lock); - DeleteCriticalSection(&_pthread_cond_test_init_lock); DeleteCriticalSection(&_pthread_mutex_test_init_lock); + DeleteCriticalSection(&_pthread_cond_test_init_lock); _pthread_processInitialized = FALSE; } } /* processTerminate */ -#ifdef _MSC_VER - -static DWORD -ExceptionFilter (EXCEPTION_POINTERS * ep, DWORD * ei) -{ - DWORD param; - DWORD numParams = ep->ExceptionRecord->NumberParameters; - - numParams = (numParams > 3) ? 3 : numParams; - - for (param = 0; param < numParams; param++) - { - ei[param] = ep->ExceptionRecord->ExceptionInformation[param]; - } - - return EXCEPTION_EXECUTE_HANDLER; -} - -#endif /* _MSC_VER */ - -#if ! defined (__MINGW32__) || defined (__MSVCRT__) -unsigned PT_STDCALL -#else -void -#endif +void * _pthread_threadStart (ThreadParms * threadParms) { - pthread_t self; + pthread_t tid; void *(*start) (void *); void *arg; -#ifdef _MSC_VER - - DWORD ei[3]; - -#endif - void * status; - self = threadParms->tid; + tid = threadParms->tid; start = threadParms->start; arg = threadParms->arg; -#if defined (__MINGW32__) && ! defined (__MSVCRT__) - /* beginthread does not return the thread id, and so we do it here. */ - self->thread = GetCurrentThreadId (); -#endif - free (threadParms); - pthread_setspecific (_pthread_selfThreadKey, self); + pthread_setspecific (_pthread_selfThreadKey, tid); #ifdef _MSC_VER @@ -200,34 +174,16 @@ _pthread_threadStart (ThreadParms * threadParms) /* * Run the caller's routine; */ - status = (*start) (arg); + (*start) (arg); + status = (void *) 0; } - __except (ExceptionFilter(GetExceptionInformation(), ei)) + __except (EXCEPTION_EXECUTE_HANDLER) { - DWORD ec = GetExceptionCode(); - - if (ec == EXCEPTION_PTHREAD_SERVICES) - { - switch (ei[0]) - { - case _PTHREAD_EPS_CANCEL: - status = PTHREAD_CANCELED; - break; - case _PTHREAD_EPS_EXIT: - status = (void *) ei[1]; - break; - default: - status = PTHREAD_CANCELED; - } - } - else - { - /* - * A system unexpected exception had occurred running the user's - * routine. We get control back within this block. - */ - status = PTHREAD_CANCELED; - } + /* + * A system unexpected exception had occurred running the user's + * routine. We get control back within this block. + */ + status = PTHREAD_CANCELED; } #else /* _MSC_VER */ @@ -239,22 +195,16 @@ _pthread_threadStart (ThreadParms * threadParms) /* * Run the caller's routine; */ - status = self->exitStatus = (*start) (arg); + (*start) (arg); + status = (void *) 0; } - catch (Pthread_exception_cancel) + catch (Pthread_exception) { /* * Thread was cancelled. */ status = PTHREAD_CANCELED; } - catch (Pthread_exception_exit) - { - /* - * Thread was exited via pthread_exit(). - */ - status = self->exitStatus; - } catch (...) { /* @@ -270,27 +220,19 @@ _pthread_threadStart (ThreadParms * threadParms) * Run the caller's routine; no cancelation or other exceptions will * be honoured. */ - status = (*start) (arg); + (*start) (arg); + status = (void *) 0; #endif /* __cplusplus */ -#endif /* _MSC_VER */ +#endif /* _WIN32 */ - _pthread_callUserDestroyRoutines(self); - -#if ! defined (__MINGW32__) || defined (__MSVCRT__) - _endthreadex ((unsigned) status); -#else - _endthread (); -#endif + pthread_exit (status); /* * Never reached. */ - -#if ! defined (__MINGW32__) || defined (__MSVCRT__) - return (unsigned) status; -#endif + return (status); } /* _pthread_threadStart */ @@ -306,13 +248,10 @@ _pthread_threadDestroy (pthread_t thread) CloseHandle (thread->cancelEvent); } -#if ! defined (__MINGW32__) || defined (__MSVCRT__) - /* See documentation for endthread vs endthreadex. */ if( thread->threadH != 0 ) { CloseHandle( thread->threadH ); } -#endif free (thread); } @@ -586,6 +525,46 @@ _pthread_callUserDestroyRoutines (pthread_t thread) } /* _pthread_callUserDestroyRoutines */ + +#ifdef NEED_FTIME + +/* + * time between jan 1, 1601 and jan 1, 1970 in units of 100 nanoseconds + */ +#define TIMESPEC_TO_FILETIME_OFFSET \ + ( ((LONGLONG) 27111902 << 32) + (LONGLONG) 3577643008 ) + +static void +timespec_to_filetime(const struct timespec *ts, FILETIME *ft) + /* + * ------------------------------------------------------------------- + * converts struct timespec + * where the time is expressed in seconds and nanoseconds from Jan 1, 1970. + * into FILETIME (as set by GetSystemTimeAsFileTime), where the time is + * expressed in 100 nanoseconds from Jan 1, 1601, + * ------------------------------------------------------------------- + */ +{ + *(LONGLONG *)ft = ts->tv_sec * 10000000 + (ts->tv_nsec + 50) / 100 + TIMESPEC_TO_FILETIME_OFFSET; +} + +static void +filetime_to_timespec(const FILETIME *ft, struct timespec *ts) + /* + * ------------------------------------------------------------------- + * converts FILETIME (as set by GetSystemTimeAsFileTime), where the time is + * expressed in 100 nanoseconds from Jan 1, 1601, + * into struct timespec + * where the time is expressed in seconds and nanoseconds from Jan 1, 1970. + * ------------------------------------------------------------------- + */ +{ + ts->tv_sec = (int)((*(LONGLONG *)ft - TIMESPEC_TO_FILETIME_OFFSET) / 10000000); + ts->tv_nsec = (int)((*(LONGLONG *)ft - TIMESPEC_TO_FILETIME_OFFSET - ((LONGLONG)ts->tv_sec * (LONGLONG)10000000)) * 100); +} + +#endif /* NEED_FTIME */ + int _pthread_sem_timedwait (sem_t * sem, const struct timespec * abstime) /* @@ -628,15 +607,21 @@ _pthread_sem_timedwait (sem_t * sem, const struct timespec * abstime) { int result = 0; +#ifdef NEED_FTIME + + struct timespec currSysTime; + +#else /* NEED_FTIME */ #if defined(__MINGW32__) struct timeb currSysTime; -#else +#else /* __MINGW32__ */ struct _timeb currSysTime; -#endif +#endif /* __MINGW32__ */ +#endif /* NEED_FTIME */ const DWORD NANOSEC_PER_MILLISEC = 1000000; const DWORD MILLISEC_PER_SEC = 1000; @@ -659,18 +644,56 @@ _pthread_sem_timedwait (sem_t * sem, const struct timespec * abstime) */ /* get current system time */ + +#ifdef NEED_FTIME + + { + FILETIME ft; + SYSTEMTIME st; + + GetSystemTime(&st); + SystemTimeToFileTime(&st, &ft); + /* + * GetSystemTimeAsFileTime(&ft); would be faster, + * but it does not exist on WinCE + */ + + filetime_to_timespec(&ft, &currSysTime); + } + + /* + * subtract current system time from abstime + */ + milliseconds = (abstime->tv_sec - currSysTime.tv_sec) * MILLISEC_PER_SEC; + milliseconds += ((abstime->tv_nsec - currSysTime.tv_nsec) + (NANOSEC_PER_MILLISEC/2)) / NANOSEC_PER_MILLISEC; + +#else /* NEED_FTIME */ _ftime(&currSysTime); - /* subtract current system time from abstime */ + /* + * subtract current system time from abstime + */ milliseconds = (abstime->tv_sec - currSysTime.time) * MILLISEC_PER_SEC; - milliseconds += (abstime->tv_nsec / NANOSEC_PER_MILLISEC) - + milliseconds += ((abstime->tv_nsec + (NANOSEC_PER_MILLISEC/2)) / NANOSEC_PER_MILLISEC) - currSysTime.millitm; +#endif /* NEED_FTIME */ + + if (((int) milliseconds) < 0) milliseconds = 0; } +#ifdef NEED_SEM + + result = (pthreadCancelableTimedWait (sem->event, milliseconds)); + +#else /* NEED_SEM */ + result = (pthreadCancelableTimedWait (*sem, milliseconds)); + +#endif + } if (result != 0) @@ -681,6 +704,12 @@ _pthread_sem_timedwait (sem_t * sem, const struct timespec * abstime) } +#ifdef NEED_SEM + + _pthread_decrease_semaphore(sem); + +#endif /* NEED_SEM */ + return 0; } /* _pthread_sem_timedwait */ diff --git a/pthread.def b/pthread.def index 6920d5a..3581dbe 100644 --- a/pthread.def +++ b/pthread.def @@ -1,110 +1,102 @@ -; pthread.def -; Last updated: $Date: 1999/09/15 00:56:22 $ - -; Currently unimplemented functions are commented out. - -LIBRARY pthread - -EXPORTS -;pthread_atfork -pthread_attr_destroy -pthread_attr_getdetachstate -;pthread_attr_getinheritsched -pthread_attr_getschedparam -;pthread_attr_getschedpolicy -;pthread_attr_getscope -pthread_attr_getstackaddr -pthread_attr_getstacksize -pthread_attr_init -pthread_attr_setdetachstate -;pthread_attr_setinheritsched -pthread_attr_setschedparam -;pthread_attr_setschedpolicy -;pthread_attr_setscope -pthread_attr_setstackaddr -pthread_attr_setstacksize -pthread_cancel -; -; These are implemented as macros -; -;pthread_cleanup_pop -;pthread_cleanup_push -; -pthread_condattr_destroy -pthread_condattr_getpshared -pthread_condattr_init -pthread_condattr_setpshared -pthread_cond_broadcast -pthread_cond_destroy -pthread_cond_init -pthread_cond_signal -pthread_cond_timedwait -pthread_cond_wait -pthread_create -pthread_detach -pthread_equal -pthread_exit -pthread_getschedparam -pthread_getspecific -pthread_join -pthread_key_create -pthread_key_delete -;pthread_kill -pthread_mutexattr_destroy -;pthread_mutexattr_getprioceiling -;pthread_mutexattr_getprotocol -pthread_mutexattr_getpshared -pthread_mutexattr_init -;pthread_mutexattr_setprioceiling -;pthread_mutexattr_setprotocol -pthread_mutexattr_setpshared -pthread_mutexattr_destroy -pthread_mutex_init -pthread_mutex_destroy -pthread_mutex_lock -pthread_mutex_trylock -pthread_mutex_unlock -pthread_once -pthread_self -pthread_setcancelstate -pthread_setcanceltype -pthread_setschedparam -pthread_setspecific -;pthread_sigmask -pthread_testcancel -; -; POSIX 1.b -; -sched_get_priority_min -sched_get_priority_max -sched_yield -sem_init -sem_destroy -sem_trywait -sem_wait -sem_post -sem_open -sem_close -sem_unlink -sem_getvalue -; -; Read/Write Locks -; -pthread_rwlock_init -pthread_rwlock_destroy -pthread_rwlock_tryrdlock -pthread_rwlock_trywrlock -pthread_rwlock_rdlock -pthread_rwlock_wrlock -pthread_rwlock_unlock -; -; Non-portable but useful -; -pthread_mutexattr_setforcecs_np -pthreadCancelableWait -pthreadCancelableTimedWait -; -; Needed if !defined(_MSC_VER) && !defined(__cplusplus) -; -pthread_push_cleanup -pthread_pop_cleanup +; pthread.def
+; Last updated: $Date: 1999/11/04 14:56:51 $
+
+; Currently unimplemented functions are commented out.
+
+LIBRARY pthread
+
+EXPORTS
+_pthread_processInitialize
+;pthread_atfork
+pthread_attr_destroy
+pthread_attr_getdetachstate
+;pthread_attr_getinheritsched
+pthread_attr_getschedparam
+;pthread_attr_getschedpolicy
+;pthread_attr_getscope
+pthread_attr_getstackaddr
+pthread_attr_getstacksize
+pthread_attr_init
+pthread_attr_setdetachstate
+;pthread_attr_setinheritsched
+pthread_attr_setschedparam
+;pthread_attr_setschedpolicy
+;pthread_attr_setscope
+pthread_attr_setstackaddr
+pthread_attr_setstacksize
+pthread_cancel
+;
+; These are implemented as macros
+;
+;pthread_cleanup_pop
+;pthread_cleanup_push
+;
+pthread_condattr_destroy
+pthread_condattr_getpshared
+pthread_condattr_init
+pthread_condattr_setpshared
+pthread_cond_broadcast
+pthread_cond_destroy
+pthread_cond_init
+pthread_cond_signal
+pthread_cond_timedwait
+pthread_cond_wait
+pthread_create
+pthread_detach
+pthread_equal
+pthread_exit
+pthread_getschedparam
+pthread_getspecific
+pthread_join
+pthread_key_create
+pthread_key_delete
+;pthread_kill
+pthread_mutexattr_destroy
+;pthread_mutexattr_getprioceiling
+;pthread_mutexattr_getprotocol
+pthread_mutexattr_getpshared
+pthread_mutexattr_init
+;pthread_mutexattr_setprioceiling
+;pthread_mutexattr_setprotocol
+pthread_mutexattr_setpshared
+pthread_mutexattr_destroy
+pthread_mutex_init
+pthread_mutex_destroy
+pthread_mutex_lock
+pthread_mutex_trylock
+pthread_mutex_unlock
+pthread_once
+pthread_self
+pthread_setcancelstate
+pthread_setcanceltype
+pthread_setschedparam
+pthread_setspecific
+;pthread_sigmask
+pthread_testcancel
+;
+; POSIX 1.b
+;
+sched_get_priority_min
+sched_get_priority_max
+sched_yield
+sem_init
+sem_destroy
+sem_trywait
+sem_wait
+sem_post
+sem_open
+sem_close
+sem_unlink
+sem_getvalue
+;
+; Non-portable but useful
+;
+pthread_mutexattr_setforcecs_np
+pthreadCancelableWait
+pthreadCancelableTimedWait
+;
+; Needed if !defined(_MSC_VER) && !defined(__cplusplus)
+;
+pthread_push_cleanup
+pthread_pop_cleanup
+
@@ -122,17 +122,6 @@ * --------------------------- * pthread_sigmask * - * --------------------------- - * Read/Write Locks: - * --------------------------- - * pthread_rwlock_init - * pthread_rwlock_destroy - * pthread_rwlock_tryrdlock - * pthread_rwlock_trywrlock - * pthread_rwlock_rdlock - * pthread_rwlock_rwlock - * pthread_rwlock_unlock - * * Limitations * =========== * The following functions are not implemented: @@ -215,7 +204,12 @@ #endif /* HAVE_CONFIG_H */ #include <windows.h> + +#ifndef NEED_FTIME #include <time.h> +#else /* NEED_FTIME */ +/* use native WIN32 time API */ +#endif /* NEED_FTIME */ #if HAVE_SIGNAL_H #include <signal.h> @@ -243,14 +237,22 @@ struct timespec { #endif /* SIG_SETMASK */ -#include <process.h> +/* + * note: ETIMEDOUT is correctly defined in winsock.h on winCE + */ +#ifdef HAVE_WINSOCK_H +#include <winsock.h> +#endif + +#ifdef NEED_ERRNO +#include "need_errno.h" +#else #include <errno.h> +#endif -#ifdef _WIN32 #ifndef ETIMEDOUT -#define ETIMEDOUT 19981220 /* Let's hope this is unique */ +#define ETIMEDOUT 19981220 /* FIXME: Need the proper value here. */ #endif -#endif /* _WIN32 */ #ifdef _MSC_VER /* @@ -264,6 +266,13 @@ struct timespec { #define FALSE 0 #endif /* !TRUE */ +#ifdef __MINGW32__ +#define PT_STDCALL +#else +#define PT_STDCALL __stdcall +#endif + + /* * This should perhaps be in autoconf or * possibly fixed in Mingw32 to @@ -376,9 +385,7 @@ extern "C" /* * POSIX Options */ -#ifndef _POSIX_THREADS #define _POSIX_THREADS -#endif #define _POSIX_THREAD_SAFE_FUNCTIONS #define _POSIX_THREAD_ATTR_STACKSIZE @@ -431,8 +438,6 @@ typedef struct pthread_mutex_t_ *pthread_mutex_t; typedef struct pthread_mutexattr_t_ *pthread_mutexattr_t; typedef struct pthread_cond_t_ *pthread_cond_t; typedef struct pthread_condattr_t_ *pthread_condattr_t; -typedef struct pthread_rwlock_t_ *pthread_rwlock_t; -typedef struct pthread_rwlockattr_t_ *pthread_rwlockattr_t; /* @@ -511,8 +516,6 @@ struct pthread_once_t_ #define PTHREAD_COND_INITIALIZER ((pthread_cond_t) -1) -#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) -1) - /* * ==================== @@ -551,14 +554,6 @@ struct sched_param { * WIN32 SEH * C * C++ - * - * Please note that exiting a push/pop block via - * "return", "exit", "break", or "continue" will - * lead to different behaviour amongst applications - * depending upon whether the library was built - * using SEH, C++, or C. For example, a library built - * with SEH will call the cleanup routine, while both - * C++ and C built versions will not. */ typedef struct _pthread_cleanup_t _pthread_cleanup_t; @@ -569,7 +564,7 @@ struct _pthread_cleanup_t void *arg; #if !defined(_MSC_VER) && !defined(__cplusplus) _pthread_cleanup_t *prev; -#endif /* !_MSC_VER && ! __cplusplus */ +#endif }; #ifdef _MSC_VER @@ -704,6 +699,12 @@ struct _pthread_cleanup_t */ /* + * Useful if an application wants to statically link + * the lib rather than load the DLL at run-time. + */ +int pthread_win32_initialize_np(void); + +/* * PThread Attribute Functions */ int pthread_attr_init (pthread_attr_t * attr); @@ -863,25 +864,6 @@ int pthread_attr_setschedparam (pthread_attr_t *attr, const struct sched_param *param); /* - * Read-Write Lock Functions - */ - -int pthread_rwlock_init(pthread_rwlock_t *lock, - const pthread_rwlockattr_t *attr); - -int pthread_rwlock_destroy(pthread_rwlock_t *lock); - -int pthread_rwlock_tryrdlock(pthread_rwlock_t *); - -int pthread_rwlock_trywrlock(pthread_rwlock_t *); - -int pthread_rwlock_rdlock(pthread_rwlock_t *lock); - -int pthread_rwlock_wrlock(pthread_rwlock_t *lock); - -int pthread_rwlock_unlock(pthread_rwlock_t *lock); - -/* * Protected Methods * * This function blocks until the given WIN32 handle @@ -902,7 +884,7 @@ int pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout); /* * Thread-Safe C Runtime Library Mappings. */ -#if ! defined( _REENTRANT ) && ! defined( _MT ) +#if (! defined(NEED_ERRNO)) || (! defined( _REENTRANT ) && ! defined( _MT )) int * _errno( void ); #endif @@ -925,8 +907,8 @@ int * _errno( void ); (_buf) ) #define ctime_r( _clock, _buf ) \ - ( strcpy( (_buf), ctime( (_tm) ) ), \ - (_buf) ) + ( strcpy( (_buf), ctime( (_tm) ) ), \ + (_buf) ) #define gmtime_r( _clock, _result ) \ ( *(_result) = *gmtime( (_clock) ), \ @@ -43,8 +43,8 @@ #endif #include <windows.h> -#include <process.h> -#include <errno.h> +//#include <process.h> +//#include <errno.h> #ifdef _MSC_VER /* diff --git a/semaphore.c b/semaphore.c index 0fcfc94..a8c346e 100644 --- a/semaphore.c +++ b/semaphore.c @@ -43,14 +43,13 @@ */ #include <windows.h> -#include <process.h> -#include <sys/timeb.h> +//#include <process.h> +//#include <sys/timeb.h> #include <string.h> #include "pthread.h" #include "semaphore.h" - int sem_init (sem_t * sem, int pshared, unsigned int value) /* @@ -90,6 +89,7 @@ sem_init (sem_t * sem, int pshared, unsigned int value) { int result = 0; + if (pshared != 0) { /* @@ -101,6 +101,22 @@ sem_init (sem_t * sem, int pshared, unsigned int value) } else { + +#ifdef NEED_SEM + + sem->value = value; + pthread_mutex_init(&sem->mutex, NULL); + sem->event = CreateEvent (NULL, + FALSE, /* manual reset */ + FALSE, /* initial state */ + NULL); + if (value != 0) + { + SetEvent(sem->event); + } + +#else /* NEED_SEM */ + /* * NOTE: Taking advantage of the fact that * sem_t is a simple structure with one entry; @@ -116,6 +132,9 @@ sem_init (sem_t * sem, int pshared, unsigned int value) { result = ENOSPC; } + +#endif /* NEED_SEM */ + } if (result != 0) @@ -161,11 +180,27 @@ sem_destroy (sem_t * sem) { result = EINVAL; } + +#ifdef NEED_SEM + + else + { + pthread_mutex_destroy(&sem->mutex); + if (!CloseHandle(sem->event)) + { + result = EINVAL; + } + } + +#else /* NEED_SEM */ + else if (! CloseHandle (*sem)) { result = EINVAL; } +#endif /* NEED_SEM */ + if (result != 0) { errno = result; @@ -213,11 +248,22 @@ sem_trywait (sem_t * sem) { result = EINVAL; } + +#ifdef NEED_SEM + + /* not yet implemented! */ + result = EINVAL; + return -1; + +#else /* NEED_SEM */ + else if (WaitForSingleObject (*sem, 0) == WAIT_TIMEOUT) { result = EAGAIN; } +#endif /* NEED_SEM */ + if (result != 0) { errno = result; @@ -229,6 +275,53 @@ sem_trywait (sem_t * sem) } /* sem_trywait */ +#ifdef NEED_SEM + +void +_pthread_decrease_semaphore(sem_t * sem) +{ + pthread_mutex_lock(&sem->mutex); + + if (sem->value != 0) + { + sem->value--; + if (sem->value != 0) + { + SetEvent(sem->event); + } + } + else + { + /* this case should not happen! */ + } + + pthread_mutex_unlock(&sem->mutex); +} + +BOOL +_pthread_increase_semaphore(sem_t * sem, unsigned int n) +{ + BOOL result; + + pthread_mutex_lock(&sem->mutex); + + if (sem->value + n > sem->value) + { + sem->value += n; + SetEvent(sem->event); + result = TRUE; + } + else + { + result = FALSE; + } + + pthread_mutex_unlock(&sem->mutex); + return result; +} + +#endif /* NEED_SEM */ + int sem_wait (sem_t * sem) /* @@ -268,7 +361,17 @@ sem_wait (sem_t * sem) } else { + +#ifdef NEED_SEM + + result = pthreadCancelableWait (sem->event); + +#else /* NEED_SEM */ + result = pthreadCancelableWait (*sem); + +#endif /* NEED_SEM */ + } if (result != 0) @@ -277,6 +380,12 @@ sem_wait (sem_t * sem) return -1; } +#ifdef NEED_SEM + + _decrease_semaphore(sem); + +#endif /* NEED_SEM */ + return 0; } /* sem_wait */ @@ -314,12 +423,21 @@ sem_post (sem_t * sem) { result = EINVAL; } + +#ifdef NEED_SEM + + else if (! _increase_semaphore (sem, 1)) + +#else /* NEED_SEM */ + else if (! ReleaseSemaphore (*sem, 1, 0)) + +#endif /* NEED_SEM */ + { result = EINVAL; } - if (result != 0) { errno = result; diff --git a/semaphore.h b/semaphore.h index fb475a0..8af8be8 100644 --- a/semaphore.h +++ b/semaphore.h @@ -28,8 +28,11 @@ #if !defined( SEMAPHORE_H ) #define SEMAPHORE_H -#include <process.h> +#ifdef NEED_ERRNO +#include "need_errno.h" +#else #include <errno.h> +#endif #define _POSIX_SEMAPHORES @@ -42,7 +45,15 @@ extern "C" typedef unsigned int mode_t; #endif +#ifdef NEED_SEM +typedef struct { + unsigned int value; + pthread_mutex_t mutex; + HANDLE event; +} sem_t; +#else /* NEED_SEM */ typedef HANDLE sem_t; +#endif /* NEED_SEM */ int sem_init (sem_t * sem, int pshared, @@ -23,7 +23,8 @@ * MA 02111-1307, USA */ -#include <errno.h> +/* errno.h or a replacement file is included by pthread.h */
+//#include <errno.h> #include "pthread.h" #include "implement.h" @@ -25,6 +25,11 @@ #include "pthread.h" #include "implement.h" +
+/* TLS_OUT_OF_INDEXES not defined on WinCE */
+#ifndef TLS_OUT_OF_INDEXES
+#define TLS_OUT_OF_INDEXES 0xffffffff
+#endif
int pthread_key_create (pthread_key_t * key, void (*destructor) (void *)) |