summaryrefslogtreecommitdiffstats
path: root/once.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2007-05-17 22:22:53 +0000
committerLennart Poettering <lennart@poettering.net>2007-05-17 22:22:53 +0000
commitbef6322859a5dc01e35d884de7afd2eabb1d9e4d (patch)
tree6431f409747005fca20998fe518c174c909fd385 /once.c
parentc58ce0879c1cabfd31dd8657d2594d78f13b1360 (diff)
at basic locking/threading support
git-svn-id: file:///home/lennart/svn/public/libsydney/trunk@26 9ba3c220-e4d3-45a2-8aa3-73fcc9aff6ce
Diffstat (limited to 'once.c')
-rw-r--r--once.c58
1 files changed, 58 insertions, 0 deletions
diff --git a/once.c b/once.c
new file mode 100644
index 0000000..de41be3
--- /dev/null
+++ b/once.c
@@ -0,0 +1,58 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pthread.h>
+#include <assert.h>
+
+#include "once.h"
+#include "mutex.h"
+#include "malloc.h"
+#include "macro.h"
+
+static sa_mutex_t *global_mutex;
+static pthread_once_t global_mutex_once = PTHREAD_ONCE_INIT;
+
+static void global_mutex_once_func(void) {
+ global_mutex = sa_mutex_new(0);
+}
+
+int sa_once(sa_once_t *control, sa_once_func_t func) {
+ int r;
+
+ assert(control);
+ assert(func);
+
+ /* Create the global mutex */
+ sa_assert_success(pthread_once(&global_mutex_once, global_mutex_once_func));
+
+ if (!global_mutex)
+ return -1;
+
+ r = 0;
+
+ /* Create the local mutex */
+ sa_mutex_lock(global_mutex);
+ if (!control->mutex) {
+ if (!(control->mutex = sa_mutex_new(1)))
+ r = -1;
+ }
+ sa_mutex_unlock(global_mutex);
+
+ if (!r)
+ return -1;
+
+ /* Execute function */
+ sa_mutex_lock(control->mutex);
+ if (!control->once_value) {
+ control->once_value = 1;
+ func();
+ }
+ sa_mutex_unlock(control->mutex);
+
+ /* 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. */
+
+ return 0;
+}