| 1 | #ifndef _LINUX_CALL_ONCE_H |
| 2 | #define _LINUX_CALL_ONCE_H |
| 3 | |
| 4 | #include <linux/types.h> |
| 5 | #include <linux/mutex.h> |
| 6 | |
| 7 | #define ONCE_NOT_STARTED 0 |
| 8 | #define ONCE_RUNNING 1 |
| 9 | #define ONCE_COMPLETED 2 |
| 10 | |
| 11 | struct once { |
| 12 | atomic_t state; |
| 13 | struct mutex lock; |
| 14 | }; |
| 15 | |
| 16 | static inline void __once_init(struct once *once, const char *name, |
| 17 | struct lock_class_key *key) |
| 18 | { |
| 19 | atomic_set(v: &once->state, ONCE_NOT_STARTED); |
| 20 | __mutex_init(lock: &once->lock, name, key); |
| 21 | } |
| 22 | |
| 23 | #define once_init(once) \ |
| 24 | do { \ |
| 25 | static struct lock_class_key __key; \ |
| 26 | __once_init((once), #once, &__key); \ |
| 27 | } while (0) |
| 28 | |
| 29 | /* |
| 30 | * call_once - Ensure a function has been called exactly once |
| 31 | * |
| 32 | * @once: Tracking struct |
| 33 | * @cb: Function to be called |
| 34 | * |
| 35 | * If @once has never completed successfully before, call @cb and, if |
| 36 | * it returns a zero or positive value, mark @once as completed. Return |
| 37 | * the value returned by @cb |
| 38 | * |
| 39 | * If @once has completed succesfully before, return 0. |
| 40 | * |
| 41 | * The call to @cb is implicitly surrounded by a mutex, though for |
| 42 | * efficiency the * function avoids taking it after the first call. |
| 43 | */ |
| 44 | static inline int call_once(struct once *once, int (*cb)(struct once *)) |
| 45 | { |
| 46 | int r, state; |
| 47 | |
| 48 | /* Pairs with atomic_set_release() below. */ |
| 49 | if (atomic_read_acquire(v: &once->state) == ONCE_COMPLETED) |
| 50 | return 0; |
| 51 | |
| 52 | guard(mutex)(T: &once->lock); |
| 53 | state = atomic_read(v: &once->state); |
| 54 | if (unlikely(state != ONCE_NOT_STARTED)) |
| 55 | return WARN_ON_ONCE(state != ONCE_COMPLETED) ? -EINVAL : 0; |
| 56 | |
| 57 | atomic_set(v: &once->state, ONCE_RUNNING); |
| 58 | r = cb(once); |
| 59 | if (r < 0) |
| 60 | atomic_set(v: &once->state, ONCE_NOT_STARTED); |
| 61 | else |
| 62 | atomic_set_release(v: &once->state, ONCE_COMPLETED); |
| 63 | return r; |
| 64 | } |
| 65 | |
| 66 | #endif /* _LINUX_CALL_ONCE_H */ |
| 67 | |