summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2007-09-14 21:04:08 +0000
committerLennart Poettering <lennart@poettering.net>2007-09-14 21:04:08 +0000
commitbf274cb617d92e55d18fa7e2f6b1cf139b96a413 (patch)
treef09697980f85c24de1bc3d0148d773f97592a43a
parent04ed0f9536f8b211d68d7df381f0fb4dd04dc0ff (diff)
add two new macros PA_ONCE_BEGIN and PA_ONCE_END which allow usage of pa_once without declaring a function to be called
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1820 fefdeb5f-60dc-0310-8127-8f9354f1896f
-rw-r--r--src/pulsecore/once-posix.c51
-rw-r--r--src/pulsecore/once.h32
2 files changed, 64 insertions, 19 deletions
diff --git a/src/pulsecore/once-posix.c b/src/pulsecore/once-posix.c
index fd6288fe..fba0ddf1 100644
--- a/src/pulsecore/once-posix.c
+++ b/src/pulsecore/once-posix.c
@@ -32,18 +32,20 @@
#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);
+ }
}
+
diff --git a/src/pulsecore/once.h b/src/pulsecore/once.h
index d9372d86..a4a0b239 100644
--- a/src/pulsecore/once.h
+++ b/src/pulsecore/once.h
@@ -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