summaryrefslogtreecommitdiffstats
path: root/src/pulsecore/once-posix.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pulsecore/once-posix.c')
-rw-r--r--src/pulsecore/once-posix.c51
1 files changed, 33 insertions, 18 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);
+ }
}
+