diff options
| author | Lennart Poettering <lennart@poettering.net> | 2007-09-14 21:04:08 +0000 | 
|---|---|---|
| committer | Lennart Poettering <lennart@poettering.net> | 2007-09-14 21:04:08 +0000 | 
| commit | bf274cb617d92e55d18fa7e2f6b1cf139b96a413 (patch) | |
| tree | f09697980f85c24de1bc3d0148d773f97592a43a | |
| parent | 04ed0f9536f8b211d68d7df381f0fb4dd04dc0ff (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.c | 51 | ||||
| -rw-r--r-- | src/pulsecore/once.h | 32 | 
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  | 
