Преглед на файлове

Made unix mutexes recursive.

Ryan C. Gordon преди 21 години
родител
ревизия
c28540fe89
променени са 2 файла, в които са добавени 41 реда и са изтрити 7 реда
  1. 2 0
      CHANGELOG
  2. 39 7
      platform/unix.c

+ 2 - 0
CHANGELOG

@@ -2,6 +2,8 @@
  * CHANGELOG.
  * CHANGELOG.
  */
  */
 
 
+09192005 - Make unix mutexes recursive above pthread layer...fixes deadlock on
+           MacOS X, for now.
 09182005 - API BREAKAGE: PHYSFS_enumerateFilesCallback() now passes the
 09182005 - API BREAKAGE: PHYSFS_enumerateFilesCallback() now passes the
            original directory name back to the app in the callback. This
            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
            API was only in 1.1.0, and wasn't promised to be stable at this

+ 39 - 7
platform/unix.c

@@ -466,6 +466,13 @@ void __PHYSFS_platformReleaseMutex(void *mutex) {}
 
 
 #else
 #else
 
 
+typedef struct
+{
+    pthread_mutex_t mutex;
+    pthread_t owner;
+    PHYSFS_uint32 count;
+} PthreadMutex;
+
 /* Just in case; this is a panic value. */
 /* Just in case; this is a panic value. */
 #if ((!defined SIZEOF_INT) || (SIZEOF_INT <= 0))
 #if ((!defined SIZEOF_INT) || (SIZEOF_INT <= 0))
 #  define SIZEOF_INT 4
 #  define SIZEOF_INT 4
@@ -490,36 +497,61 @@ PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
 void *__PHYSFS_platformCreateMutex(void)
 void *__PHYSFS_platformCreateMutex(void)
 {
 {
     int rc;
     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);
     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)
     if (rc != 0)
     {
     {
         allocator.Free(m);
         allocator.Free(m);
         BAIL_MACRO(strerror(rc), NULL);
         BAIL_MACRO(strerror(rc), NULL);
     } /* if */
     } /* if */
 
 
+    m->count = 0;
+    m->owner = (pthread_t) 0xDEADBEEF;
     return((void *) m);
     return((void *) m);
 } /* __PHYSFS_platformCreateMutex */
 } /* __PHYSFS_platformCreateMutex */
 
 
 
 
 void __PHYSFS_platformDestroyMutex(void *mutex)
 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 */
 } /* __PHYSFS_platformDestroyMutex */
 
 
 
 
 int __PHYSFS_platformGrabMutex(void *mutex)
 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 */
 } /* __PHYSFS_platformGrabMutex */
 
 
 
 
 void __PHYSFS_platformReleaseMutex(void *mutex)
 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 */
 } /* __PHYSFS_platformReleaseMutex */
 
 
 #endif /* !PHYSFS_NO_PTHREADS_SUPPORT */
 #endif /* !PHYSFS_NO_PTHREADS_SUPPORT */