On Fri, Jul 17, 2020 at 10:28:18PM -0700, Eric Biggers wrote:
> /**
>  * INIT_ONCE() - do one-time initialization
>  * @done: pointer to a 'bool' flag that tracks whether initialization has been
>  *      done yet or not.  Must be false by default.
>  * @mutex: pointer to a mutex to use to synchronize executions of @init_func
>  * @init_func: the one-time initialization function
>  * @...: additional arguments to pass to @init_func (optional)
>  *
>  * This is a more general version of DO_ONCE_BLOCKING() which supports
>  * non-static data by allowing the user to specify their own 'done' flag and
>  * mutex.
>  *
>  * Return: 0 on success (done or already done), or a negative errno value
>  *       returned by @init_func.

It might be worth pointing out explicitly that init_func can be called 
multiple times, if it returns an error.

>  */
> #define INIT_ONCE(done, mutex, init_func, ...)                                
> \
> ({                                                                    \
>       int err = 0;                                                    \
>                                                                       \
>       if (!smp_load_acquire(done)) {                                  \
>               mutex_lock(mutex);                                      \
>               if (!*(done)) {                                         \
>                       err = init_func(__VA_ARGS__);                   \
>                       if (!err)                                       \
>                               smp_store_release((done), true);        \
>               }                                                       \
>               mutex_unlock(mutex);                                    \
>       }                                                               \
>       err;                                                            \
> })

If this macro is invoked in multiple places for the same object (which 
is not unlikely), there is a distinct risk that people will supply 
different mutexes or done variables for the invocations.

IMO a better approach would be to have a macro which, given a variable 
name v, generates an actual init_once_v() function.  Then code wanting 
to use v would call init_once_v() first, with no danger of inconsistent 
usage.  You can fill in the details...

Alan Stern

Reply via email to