From e121b938c9f012958196a3141f04a3fd4f58bdb9 Mon Sep 17 00:00:00 2001 From: rpj Date: Thu, 31 May 2001 02:01:47 +0000 Subject: 2001-05-30 Ross Johnson * pthread.h (rand_r): Fake using _seed argument to quell compiler warning (compiler should optimise this away later). * GNUmakefile (OPT): Leave symbolic information out of the library and increase optimisation level - for smaller faster prebuilt dlls. 2001-05-29 Ross Johnson Contributed by - Milan Gardian * Makefile: fix typo. * pthreads.h: Fix problems with stdcall/cdecl conventions, in particular remove the need for PT_STDCALL everywhere; remove warning supression. * (errno): Fix the longstanding "inconsistent dll linkage" problem with errno; now also works with /MD debugging libs - warnings emerged when compiling pthreads library with /MD (or /MDd) compiler switch, instead of /MT (or /MTd) (i.e. when compiling pthreads using Multithreaded DLL CRT instead of Multithreaded statically linked CRT). * create.c (pthread_create): Likewise; fix typo. * private.c (ptw32_threadStart): Eliminate use of terminate() which doesn't throw exceptions. * Remove unnecessary #includes from a number of modules - [I had to #include malloc.h in implement.h for gcc - rpj]. 2001-05-29 Ross Johnson Contributed by - Thomas Pfaff * pthread.h (PTHREAD_MUTEX_DEFAULT): New; equivalent to PTHREAD_MUTEX_DEFAULT_NP. * (PTHREAD_MUTEX_NORMAL): Similarly. * (PTHREAD_MUTEX_ERRORCHECK): Similarly. * (PTHREAD_MUTEX_RECURSIVE): Similarly. * (pthread_mutex_setdefaultkind_np): New; Linux compatibility stub for pthread_mutexattr_settype. * (pthread_mutexattr_getkind_np): New; Linux compatibility stub for pthread_mutexattr_gettype. * mutex.c (pthread_mutexattr_settype): New; allow the following types of mutex: PTHREAD_MUTEX_DEFAULT_NP PTHREAD_MUTEX_NORMAL_NP PTHREAD_MUTEX_ERRORCHECK_NP PTHREAD_MUTEX_RECURSIVE_NP * Note that PTHREAD_MUTEX_DEFAULT is equivalent to PTHREAD_MUTEX_NORMAL - ie. mutexes should no longer be recursive by default, and a thread will deadlock if it tries to relock a mutex it already owns. This is inline with other pthreads implementations. * (pthread_mutex_lock): Process the lock request according to the mutex type. * (pthread_mutex_init): Eliminate use of Win32 mutexes as the basis of POSIX mutexes - instead, a combination of one critical section and one semaphore are used in conjunction with Win32 Interlocked* routines. * (pthread_mutex_destroy): Likewise. * (pthread_mutex_lock): Likewise. * (pthread_mutex_trylock): Likewise. * (pthread_mutex_unlock): Likewise. * Use longjmp/setjmp to implement cancelation when building the library using a C compiler which doesn't support exceptions, e.g. gcc -x c (note that gcc -x c++ uses exceptions). * Also fixed some of the same typos and eliminated PT_STDCALL as Milan Gardian's patches above. 2001-02-07 Ross Johnson Contributed by - Alexander Terekhov * rwlock.c: Revamped. * implement.h (pthread_rwlock_t_): Redefined. This implementation does not have reader/writer starvation problem. Rwlock attempts to behave more like a normal mutex with races and scheduling policy determining who is more important; It also supports recursive locking, has less synchronization overhead (no broadcasts at all, readers are not blocked on any condition variable) and seem to be faster than the current implementation [W98 appears to be approximately 15 percent faster at least - on top of speed increase from Thomas Pfaff's changes to mutex.c - rpj]. --- mutex.c | 331 +++++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 201 insertions(+), 130 deletions(-) (limited to 'mutex.c') diff --git a/mutex.c b/mutex.c index 3e4722e..6c64cd5 100644 --- a/mutex.c +++ b/mutex.c @@ -23,9 +23,6 @@ * MA 02111-1307, USA */ -/* errno.h or a replacement file is included by pthread.h */ -//#include - #include "pthread.h" #include "implement.h" @@ -104,10 +101,6 @@ pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) goto FAIL0; } - mx->mutex = 0; - mx->lockCount = 0; - mx->ownerThread = NULL; - if (attr != NULL && *attr != NULL && (*attr)->pshared == PTHREAD_PROCESS_SHARED @@ -125,61 +118,27 @@ pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) #error ERROR [__FILE__, line __LINE__]: Process shared mutexes are not supported yet. - mx->mutex = CreateMutex(NULL, FALSE, "FIXME FIXME FIXME"); - - if (mx->mutex == 0) - { - result = EAGAIN; - } #else result = ENOSYS; + goto FAIL0; #endif /* _POSIX_THREAD_PROCESS_SHARED */ + } - else + + mx->lock_idx = PTW32_MUTEX_LOCK_IDX_INIT; + mx->recursive_count = 0; + mx->kind = attr == NULL || *attr == NULL ? ptw32_mutex_default_kind : (*attr)->kind; + mx->ownerThread = NULL; + InitializeCriticalSection( &mx->try_lock_cs ); + mx->wait_sema = CreateSemaphore( NULL, 0, 1, NULL ); + + if( NULL == mx->wait_sema ) { - if (ptw32_try_enter_critical_section != NULL - || (attr != NULL - && *attr != NULL - && (*attr)->forcecs == 1) - ) - { - /* - * Create a critical section. - */ - InitializeCriticalSection(&mx->cs); - - /* - * Check that it works ok - since InitializeCriticalSection doesn't - * return success or failure. - */ - if ((*ptw32_try_enter_critical_section)(&mx->cs)) - { - LeaveCriticalSection(&mx->cs); - } - else - { - DeleteCriticalSection(&mx->cs); - result = EAGAIN; - } - } - else - { - /* - * Create a mutex that can only be used within the - * current process - */ - mx->mutex = CreateMutex (NULL, - FALSE, - NULL); - - if (mx->mutex == 0) - { - result = EAGAIN; - } - } + DeleteCriticalSection( &mx->try_lock_cs ); + result = EAGAIN; } if (result != 0 && mx != NULL) @@ -213,8 +172,11 @@ pthread_mutex_destroy(pthread_mutex_t *mutex) { mx = *mutex; - if ((result = pthread_mutex_trylock(&mx)) == 0) + result = pthread_mutex_trylock(&mx); + + if (result == 0 || pthread_equal( mx->ownerThread, pthread_self() ) ) { + /* * FIXME!!! * The mutex isn't held by another thread but we could still @@ -224,20 +186,12 @@ pthread_mutex_destroy(pthread_mutex_t *mutex) */ *mutex = NULL; - pthread_mutex_unlock(&mx); - - if (mx->mutex == 0) - { - DeleteCriticalSection(&mx->cs); - } - else - { - result = (CloseHandle (mx->mutex) ? 0 : EINVAL); - } + result = pthread_mutex_unlock(&mx); if (result == 0) { - mx->mutex = 0; + DeleteCriticalSection( &mx->try_lock_cs ); + CloseHandle( mx->wait_sema ); free(mx); } else @@ -321,6 +275,9 @@ pthread_mutexattr_init (pthread_mutexattr_t * attr) result = ENOMEM; } + ma->pshared = PTHREAD_PROCESS_PRIVATE; + ma->kind = ptw32_mutex_default_kind; + *attr = ma; return (result); @@ -360,7 +317,6 @@ pthread_mutexattr_destroy (pthread_mutexattr_t * attr) if (attr == NULL || *attr == NULL) { result = EINVAL; - } else { @@ -506,6 +462,7 @@ pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, { result = 0; } + (*attr)->pshared = pshared; } else @@ -518,12 +475,138 @@ pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, } /* pthread_mutexattr_setpshared */ +int +pthread_mutexattr_settype (pthread_mutexattr_t * attr, + int kind) + /* + * ------------------------------------------------------ + * + * DOCPUBLIC + * The pthread_mutexattr_settype() and + * pthread_mutexattr_gettype() functions respectively set and + * get the mutex type attribute. This attribute is set in the + * type parameter to these functions. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_mutexattr_t + * + * type + * must be one of: + * + * PTHREAD_MUTEX_DEFAULT + * + * PTHREAD_MUTEX_NORMAL + * + * PTHREAD_MUTEX_ERRORCHECK + * + * PTHREAD_MUTEX_RECURSIVE + * + * DESCRIPTION + * The pthread_mutexattr_settype() and + * pthread_mutexattr_gettype() functions respectively set and + * get the mutex type attribute. This attribute is set in the + * type parameter to these functions. The default value of the + * type attribute is PTHREAD_MUTEX_DEFAULT. + * + * The type of mutex is contained in the type attribute of the + * mutex attributes. Valid mutex types include: + * + * PTHREAD_MUTEX_NORMAL + * This type of mutex does not detect deadlock. A + * thread attempting to relock this mutex without + * first unlocking it will deadlock. Attempting to + * unlock a mutex locked by a different thread + * results in undefined behavior. Attempting to + * unlock an unlocked mutex results in undefined + * behavior. + * + * PTHREAD_MUTEX_ERRORCHECK + * This type of mutex provides error checking. A + * thread attempting to relock this mutex without + * first unlocking it will return with an error. A + * thread attempting to unlock a mutex which another + * thread has locked will return with an error. A + * thread attempting to unlock an unlocked mutex will + * return with an error. + * + * PTHREAD_MUTEX_DEFAULT + * Same as PTHREAD_MUTEX_NORMAL. + * + * PTHREAD_MUTEX_RECURSIVE + * A thread attempting to relock this mutex without + * first unlocking it will succeed in locking the + * mutex. The relocking deadlock which can occur with + * mutexes of type PTHREAD_MUTEX_NORMAL cannot occur + * with this type of mutex. Multiple locks of this + * mutex require the same number of unlocks to + * release the mutex before another thread can + * acquire the mutex. A thread attempting to unlock a + * mutex which another thread has locked will return + * with an error. A thread attempting to unlock an + * unlocked mutex will return with an error. This + * type of mutex is only supported for mutexes whose + * process shared attribute is + * PTHREAD_PROCESS_PRIVATE. + * + * RESULTS + * 0 successfully set attribute, + * EINVAL 'attr' or 'type' is invalid, + * + * ------------------------------------------------------ + */ +{ + int result = 0; + + if ((attr != NULL && *attr != NULL)) + { + switch (kind) + { + case PTHREAD_MUTEX_FAST_NP: + case PTHREAD_MUTEX_RECURSIVE_NP: + case PTHREAD_MUTEX_ERRORCHECK_NP: + (*attr)->kind = kind; + break; + default: + result = EINVAL; + break; + } + } + else + { + result = EINVAL; + } + + return (result); +} /* pthread_mutexattr_settype */ + + +int +pthread_mutexattr_gettype (pthread_mutexattr_t * attr, + int *kind) +{ + int result = 0; + + if (attr != NULL && *attr != NULL && kind != NULL) + { + *kind = (*attr)->kind; + } + else + { + result = EINVAL; + } + + return (result); +} + + int pthread_mutex_lock(pthread_mutex_t *mutex) { int result = 0; pthread_mutex_t mx; + if (mutex == NULL || *mutex == NULL) { return EINVAL; @@ -542,25 +625,33 @@ pthread_mutex_lock(pthread_mutex_t *mutex) mx = *mutex; - if (result == 0) + if( 0 == InterlockedIncrement( &mx->lock_idx ) ) { - if (mx->mutex == 0) - { - EnterCriticalSection(&mx->cs); - } - else - { - result = (WaitForSingleObject(mx->mutex, INFINITE) - == WAIT_OBJECT_0) - ? 0 - : EINVAL; - } + mx->recursive_count = 1; + mx->ownerThread = pthread_self(); } - - if (result == 0) + else { - mx->ownerThread = pthread_self(); - mx->lockCount++; + if( mx->kind != PTHREAD_MUTEX_FAST_NP && + pthread_equal( mx->ownerThread, pthread_self() ) ) + { + mx->lock_idx--; + + if( mx->kind == PTHREAD_MUTEX_RECURSIVE_NP ) + { + mx->recursive_count++; + } + else + { + result = EDEADLK; + } + } + else + { + WaitForSingleObject( mx->wait_sema, INFINITE ); + mx->recursive_count = 1; + mx->ownerThread = pthread_self(); + } } return(result); @@ -586,38 +677,22 @@ pthread_mutex_unlock(pthread_mutex_t *mutex) */ if (mx != (pthread_mutex_t) PTW32_OBJECT_AUTO_INIT) { - pthread_t self = pthread_self(); - - if (pthread_equal(mx->ownerThread, self)) + if (pthread_equal(mx->ownerThread, pthread_self())) { - int oldCount = mx->lockCount; - pthread_t oldOwner = mx->ownerThread; - - if (mx->lockCount > 0) - { - mx->lockCount--; - } - - if (mx->lockCount == 0) + if( mx->kind != PTHREAD_MUTEX_RECURSIVE_NP || + 0 == --mx->recursive_count ) { mx->ownerThread = NULL; - } - if (mx->mutex == 0) - { - LeaveCriticalSection(&mx->cs); - } - else - { - if (!ReleaseMutex(mx->mutex)) + EnterCriticalSection( &mx->try_lock_cs ); + + if( InterlockedDecrement( &mx->lock_idx ) >= 0 ) { - result = EINVAL; - /* - * Put things back the way they were. - */ - mx->lockCount = oldCount; - mx->ownerThread = oldOwner; + /* Someone is waiting on that mutex */ + ReleaseSemaphore( mx->wait_sema, 1, NULL ); } + + LeaveCriticalSection( &mx->try_lock_cs ); } } else @@ -659,32 +734,28 @@ pthread_mutex_trylock(pthread_mutex_t *mutex) if (result == 0) { - if (mx->mutex == 0) + /* Try to lock only if mutex seems available */ + if( PTW32_MUTEX_LOCK_IDX_INIT == mx->lock_idx ) { - if ((*ptw32_try_enter_critical_section)(&mx->cs) != TRUE) - { - result = EBUSY; - } - } - else - { - DWORD status; + EnterCriticalSection( &mx->try_lock_cs ); - status = WaitForSingleObject (mx->mutex, 0); - - if (status != WAIT_OBJECT_0) + if( 0 == InterlockedIncrement( &mx->lock_idx ) ) { - result = ((status == WAIT_TIMEOUT) - ? EBUSY - : EINVAL); + mx->recursive_count = 1; + mx->ownerThread = pthread_self(); } - } - } + else + { + mx->lock_idx--; + result = EBUSY; + } - if (result == 0) - { - mx->ownerThread = pthread_self(); - mx->lockCount++; + LeaveCriticalSection( &mx->try_lock_cs ); + } + else + { + result = EBUSY; + } } return(result); -- cgit v1.2.3