add two new macros PA_ONCE_BEGIN and PA_ONCE_END which allow usage of pa_once without...
authorLennart Poettering <lennart@poettering.net>
Fri, 14 Sep 2007 21:04:08 +0000 (21:04 +0000)
committerLennart Poettering <lennart@poettering.net>
Fri, 14 Sep 2007 21:04:08 +0000 (21:04 +0000)
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1820 fefdeb5f-60dc-0310-8127-8f9354f1896f

src/pulsecore/once-posix.c
src/pulsecore/once.h

index fd6288f..fba0ddf 100644 (file)
 
 #include "once.h"
 
-/* Not reentrant -- how could it be? */
-void pa_run_once(pa_once *control, pa_once_func_t func) {
+int pa_once_begin(pa_once *control) {
     pa_mutex *m;
 
     pa_assert(control);
-    pa_assert(func);
 
     if (pa_atomic_load(&control->done))
-        return;
+        return 0;
 
     pa_atomic_inc(&control->ref);
 
+    /* Caveat: We have to make sure that the once func has completed
+     * before returning, even if the once func is not actually
+     * executed by us. Hence the awkward locking. */
+    
     for (;;) {
 
         if ((m = pa_atomic_ptr_load(&control->mutex))) {
@@ -51,33 +53,46 @@ void pa_run_once(pa_once *control, pa_once_func_t func) {
             /* The mutex is stored in locked state, hence let's just
              * wait until it is unlocked */
             pa_mutex_lock(m);
-            pa_mutex_unlock(m);
-            break;
+
+            pa_once_end(control);
+            return 0;
         }
 
         pa_assert_se(m = pa_mutex_new(0));
         pa_mutex_lock(m);
 
-        if (pa_atomic_ptr_cmpxchg(&control->mutex, NULL, m)) {
-            func();
-            pa_atomic_store(&control->done, 1);
-            pa_mutex_unlock(m);
-
-            break;
-        }
+        if (pa_atomic_ptr_cmpxchg(&control->mutex, NULL, m))
+            return 1;
 
         pa_mutex_unlock(m);
         pa_mutex_free(m);
     }
+}
+
+void pa_once_end(pa_once *control) {
+    pa_mutex *m;
+    
+    pa_assert(control);
 
-    pa_assert(pa_atomic_load(&control->done));
+    pa_atomic_store(&control->done, 1);
+
+    pa_assert_se(m = pa_atomic_ptr_load(&control->mutex));
+    pa_mutex_unlock(m);
 
     if (pa_atomic_dec(&control->ref) <= 1) {
-        pa_assert(pa_atomic_ptr_cmpxchg(&control->mutex, m, NULL));
+        pa_assert_se(pa_atomic_ptr_cmpxchg(&control->mutex, m, NULL));
         pa_mutex_free(m);
     }
+}
 
-    /* Caveat: We have to make sure that the once func has completed
-     * before returning, even if the once func is not actually
-     * executed by us. Hence the awkward locking. */
+/* Not reentrant -- how could it be? */
+void pa_run_once(pa_once *control, pa_once_func_t func) {
+    pa_assert(control);
+    pa_assert(func);
+
+    if (pa_once_begin(control)) {
+        func();
+        pa_once_end(control);
+    }
 }
+
index d9372d8..a4a0b23 100644 (file)
@@ -39,8 +39,38 @@ typedef struct pa_once {
         .done = PA_ATOMIC_INIT(0)                                       \
     }
 
-typedef void (*pa_once_func_t) (void);
+/* Not to be called directly, use the macros defined below instead */
+int pa_once_begin(pa_once *o);
+void pa_once_end(pa_once *o);
+
+#define PA_ONCE_BEGIN                                                   \
+    do {                                                                \
+        static pa_once _once = PA_ONCE_INIT;                            \
+        if (pa_once_begin(&_once)) {{
+
+#define PA_ONCE_END                                                     \
+            }                                                           \
+            pa_once_end(&_once);                                        \
+        }                                                               \
+    } while(0)
 
+/*
+  
+  Usage of these macros is like this:
+  void foo() {
+      PA_ONCE_BEGIN {
+          ... stuff to be called just once ...
+  
+      } PA_ONCE_END;
+  }
+  
+*/
+
+/* Same API but calls a function */
+typedef void (*pa_once_func_t) (void);
 void pa_run_once(pa_once *o, pa_once_func_t f);
 
 #endif