Sfoglia il codice sorgente

Made unix mutexes recursive.

Ryan C. Gordon 20 anni fa
parent
commit
c28540fe89
2 ha cambiato i file con 41 aggiunte e 7 eliminazioni
  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 */