vlc | branch: master | Rémi Denis-Courmont <r...@remlab.net> | Mon Feb 24 21:31:37 2020 +0200| [07f65e3381414ebbf83f92c0602b30d411dbc56b] | committer: Rémi Denis-Courmont
threads: generic one-time initializer > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=07f65e3381414ebbf83f92c0602b30d411dbc56b --- include/vlc_threads.h | 20 ++++++++++++++++++++ src/misc/threads.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/include/vlc_threads.h b/include/vlc_threads.h index 131e319622..b04a3305c1 100644 --- a/include/vlc_threads.h +++ b/include/vlc_threads.h @@ -633,6 +633,25 @@ VLC_API void vlc_rwlock_unlock(vlc_rwlock_t *); /** @} */ +#ifndef __cplusplus +#if 0 +/** + * One-time initialization. + * + * A one-time initialization object must always be initialized assigned to + * \ref VLC_STATIC_ONCE before use. + */ +typedef struct +{ + atomic_uint value; +} vlc_once_t; + +/** + * Static initializer for one-time initialization. + */ +#define VLC_STATIC_ONCE { ATOMIC_VAR_INIT(0) } +#endif + /** * Executes a function one time. * @@ -650,6 +669,7 @@ VLC_API void vlc_rwlock_unlock(vlc_rwlock_t *); * \param cb callback to execute (the first time) */ VLC_API void vlc_once(vlc_once_t *restrict once, void (*cb)(void)); +#endif /** * \defgroup threadvar Thread-specific variables diff --git a/src/misc/threads.c b/src/misc/threads.c index b1eb9888f2..11c46fa730 100644 --- a/src/misc/threads.c +++ b/src/misc/threads.c @@ -533,3 +533,43 @@ int vlc_sem_timedwait(vlc_sem_t *sem, vlc_tick_t deadline) return 0; } + +#if 0 +enum { VLC_ONCE_UNDONE, VLC_ONCE_DOING, VLC_ONCE_CONTEND, VLC_ONCE_DONE }; + +void vlc_once(vlc_once_t *restrict once, void (*cb)(void)) +{ + unsigned int value = VLC_ONCE_UNDONE; + + if (atomic_compare_exchange_strong_explicit(&once->value, &value, + VLC_ONCE_DOING, + memory_order_acquire, + memory_order_acquire)) { + /* First time: run the callback */ + cb(); + + if (atomic_exchange_explicit(&once->value, VLC_ONCE_DONE, + memory_order_release) == VLC_ONCE_CONTEND) + /* Notify waiters if any */ + vlc_atomic_notify_all(&once->value); + + return; + } + + assert(value >= VLC_ONCE_DOING); + + if (unlikely(value == VLC_ONCE_DOING) + && atomic_compare_exchange_strong_explicit(&once->value, &value, + VLC_ONCE_CONTEND, + memory_order_acquire, + memory_order_acquire)) + value = VLC_ONCE_CONTEND; + + assert(value >= VLC_ONCE_CONTEND); + + while (unlikely(value != VLC_ONCE_DONE)) { + vlc_atomic_wait(&once->value, VLC_ONCE_CONTEND); + value = atomic_load_explicit(&once->value, memory_order_acquire); + } +} +#endif _______________________________________________ vlc-commits mailing list vlc-commits@videolan.org https://mailman.videolan.org/listinfo/vlc-commits