diff options
author | Lennart Poettering <lennart@poettering.net> | 2007-05-17 22:22:53 +0000 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2007-05-17 22:22:53 +0000 |
commit | bef6322859a5dc01e35d884de7afd2eabb1d9e4d (patch) | |
tree | 6431f409747005fca20998fe518c174c909fd385 /once.c | |
parent | c58ce0879c1cabfd31dd8657d2594d78f13b1360 (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.c | 58 |
1 files changed, 58 insertions, 0 deletions
@@ -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; +} |