compat/os2threads: Improve pthread_cond_xxx() functions
authorKO Myung-Hun <komh78@gmail.com>
Sun, 14 Feb 2016 15:20:33 +0000 (00:20 +0900)
committerMichael Niedermayer <michael@niedermayer.cc>
Sun, 14 Feb 2016 18:17:36 +0000 (19:17 +0100)
1. Manipulate waiting count in pthread_cond_wait()
2. Use builtin atomic functions to manipulate waiting count

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
compat/os2threads.h

index 7c0fe13..12cb7b0 100644 (file)
@@ -32,6 +32,7 @@
 #undef __STRICT_ANSI__          /* for _beginthread() */
 #include <stdlib.h>
 
+#include <sys/builtin.h>
 #include <sys/fmutex.h>
 
 #include "libavutil/mem.h"
@@ -43,8 +44,9 @@ typedef HMTX pthread_mutex_t;
 typedef void pthread_mutexattr_t;
 
 typedef struct {
-    HEV  event_sem;
-    int  wait_count;
+    HEV event_sem;
+    HEV ack_sem;
+    volatile unsigned  wait_count;
 } pthread_cond_t;
 
 typedef void pthread_condattr_t;
@@ -124,6 +126,7 @@ static av_always_inline int pthread_mutex_unlock(pthread_mutex_t *mutex)
 static av_always_inline int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
 {
     DosCreateEventSem(NULL, &cond->event_sem, DCE_POSTONE, FALSE);
+    DosCreateEventSem(NULL, &cond->ack_sem, DCE_POSTONE, FALSE);
 
     cond->wait_count = 0;
 
@@ -133,16 +136,16 @@ static av_always_inline int pthread_cond_init(pthread_cond_t *cond, const pthrea
 static av_always_inline int pthread_cond_destroy(pthread_cond_t *cond)
 {
     DosCloseEventSem(cond->event_sem);
+    DosCloseEventSem(cond->ack_sem);
 
     return 0;
 }
 
 static av_always_inline int pthread_cond_signal(pthread_cond_t *cond)
 {
-    if (cond->wait_count > 0) {
+    if (!__atomic_cmpxchg32(&cond->wait_count, 0, 0)) {
         DosPostEventSem(cond->event_sem);
-
-        cond->wait_count--;
+        DosWaitEventSem(cond->ack_sem, SEM_INDEFINITE_WAIT);
     }
 
     return 0;
@@ -150,23 +153,24 @@ static av_always_inline int pthread_cond_signal(pthread_cond_t *cond)
 
 static av_always_inline int pthread_cond_broadcast(pthread_cond_t *cond)
 {
-    while (cond->wait_count > 0) {
-        DosPostEventSem(cond->event_sem);
-
-        cond->wait_count--;
-    }
+    while (!__atomic_cmpxchg32(&cond->wait_count, 0, 0))
+        pthread_cond_signal(cond);
 
     return 0;
 }
 
 static av_always_inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
 {
-    cond->wait_count++;
+    __atomic_increment(&cond->wait_count);
 
     pthread_mutex_unlock(mutex);
 
     DosWaitEventSem(cond->event_sem, SEM_INDEFINITE_WAIT);
 
+    __atomic_decrement(&cond->wait_count);
+
+    DosPostEventSem(cond->ack_sem);
+
     pthread_mutex_lock(mutex);
 
     return 0;