From c28540fe89d8a9af52b1ac39be384e04f1ab002f Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 20 Sep 2005 04:01:36 +0000 Subject: [PATCH] Made unix mutexes recursive. --- CHANGELOG | 2 ++ platform/unix.c | 46 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b65fbd44..74b230bf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,8 @@ * CHANGELOG. */ +09192005 - Make unix mutexes recursive above pthread layer...fixes deadlock on + MacOS X, for now. 09182005 - API BREAKAGE: PHYSFS_enumerateFilesCallback() now passes the original directory name back to the app in the callback. This API was only in 1.1.0, and wasn't promised to be stable at this diff --git a/platform/unix.c b/platform/unix.c index 8843fd81..531500b1 100644 --- a/platform/unix.c +++ b/platform/unix.c @@ -466,6 +466,13 @@ void __PHYSFS_platformReleaseMutex(void *mutex) {} #else +typedef struct +{ + pthread_mutex_t mutex; + pthread_t owner; + PHYSFS_uint32 count; +} PthreadMutex; + /* Just in case; this is a panic value. */ #if ((!defined SIZEOF_INT) || (SIZEOF_INT <= 0)) # define SIZEOF_INT 4 @@ -490,36 +497,61 @@ PHYSFS_uint64 __PHYSFS_platformGetThreadID(void) void *__PHYSFS_platformCreateMutex(void) { int rc; - pthread_mutex_t *m; - m = (pthread_mutex_t *) allocator.Malloc(sizeof (pthread_mutex_t)); + PthreadMutex *m = (PthreadMutex *) allocator.Malloc(sizeof (PthreadMutex)); BAIL_IF_MACRO(m == NULL, ERR_OUT_OF_MEMORY, NULL); - rc = pthread_mutex_init(m, NULL); + rc = pthread_mutex_init(&m->mutex, NULL); if (rc != 0) { allocator.Free(m); BAIL_MACRO(strerror(rc), NULL); } /* if */ + m->count = 0; + m->owner = (pthread_t) 0xDEADBEEF; return((void *) m); } /* __PHYSFS_platformCreateMutex */ void __PHYSFS_platformDestroyMutex(void *mutex) { - pthread_mutex_destroy((pthread_mutex_t *) mutex); - allocator.Free(mutex); + PthreadMutex *m = (PthreadMutex *) mutex; + + /* Destroying a locked mutex is a bug, but we'll try to be helpful. */ + if ((m->owner == pthread_self()) && (m->count > 0)) + pthread_mutex_unlock(&m->mutex); + + pthread_mutex_destroy(&m->mutex); + allocator.Free(m); } /* __PHYSFS_platformDestroyMutex */ int __PHYSFS_platformGrabMutex(void *mutex) { - return(pthread_mutex_lock((pthread_mutex_t *) mutex) == 0); + PthreadMutex *m = (PthreadMutex *) mutex; + pthread_t tid = pthread_self(); + if (m->owner != tid) + { + if (pthread_mutex_lock(&m->mutex) != 0) + return(0); + m->owner = tid; + } /* if */ + + m->count++; + return(1); } /* __PHYSFS_platformGrabMutex */ void __PHYSFS_platformReleaseMutex(void *mutex) { - pthread_mutex_unlock((pthread_mutex_t *) mutex); + PthreadMutex *m = (PthreadMutex *) mutex; + if (m->owner == pthread_self()) + { + if (--m->count == 0) + { + m->owner = (pthread_t) 0xDEADBEEF; + pthread_mutex_unlock(&m->mutex); + } /* if */ + } /* if */ } /* __PHYSFS_platformReleaseMutex */ #endif /* !PHYSFS_NO_PTHREADS_SUPPORT */