87 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2#ifndef _LINUX_ONCE_H3#define _LINUX_ONCE_H4 5#include <linux/types.h>6#include <linux/jump_label.h>7 8/* Helpers used from arbitrary contexts.9 * Hard irqs are blocked, be cautious.10 */11bool __do_once_start(bool *done, unsigned long *flags);12void __do_once_done(bool *done, struct static_key_true *once_key,13 unsigned long *flags, struct module *mod) HWJS_SUSPENDS;14 15/* Variant for process contexts only. */16bool __do_once_sleepable_start(bool *done) HWJS_SUSPENDS;17void __do_once_sleepable_done(bool *done, struct static_key_true *once_key,18 struct module *mod) HWJS_SUSPENDS;19 20/* Call a function exactly once. The idea of DO_ONCE() is to perform21 * a function call such as initialization of random seeds, etc, only22 * once, where DO_ONCE() can live in the fast-path. After @func has23 * been called with the passed arguments, the static key will patch24 * out the condition into a nop. DO_ONCE() guarantees type safety of25 * arguments!26 *27 * Note that the following is not equivalent ...28 *29 * DO_ONCE(func, arg);30 * DO_ONCE(func, arg);31 *32 * ... to this version:33 *34 * void foo(void)35 * {36 * DO_ONCE(func, arg);37 * }38 *39 * foo();40 * foo();41 *42 * In case the one-time invocation could be triggered from multiple43 * places, then a common helper function must be defined, so that only44 * a single static key will be placed there!45 */46#define DO_ONCE(func, ...) \47 ({ \48 bool ___ret = false; \49 static bool __section(".data.once") ___done = false; \50 static DEFINE_STATIC_KEY_TRUE(___once_key); \51 if (static_branch_unlikely(&___once_key)) { \52 unsigned long ___flags; \53 ___ret = __do_once_start(&___done, &___flags); \54 if (unlikely(___ret)) { \55 func(__VA_ARGS__); \56 __do_once_done(&___done, &___once_key, \57 &___flags, THIS_MODULE); \58 } \59 } \60 ___ret; \61 })62 63/* Variant of DO_ONCE() for process/sleepable contexts. */64#define DO_ONCE_SLEEPABLE(func, ...) \65 ({ \66 bool ___ret = false; \67 static bool __section(".data.once") ___done = false; \68 static DEFINE_STATIC_KEY_TRUE(___once_key); \69 if (static_branch_unlikely(&___once_key)) { \70 ___ret = __do_once_sleepable_start(&___done); \71 if (unlikely(___ret)) { \72 func(__VA_ARGS__); \73 __do_once_sleepable_done(&___done, &___once_key,\74 THIS_MODULE); \75 } \76 } \77 ___ret; \78 })79 80#define get_random_once(buf, nbytes) \81 DO_ONCE(get_random_bytes, (buf), (nbytes))82 83#define get_random_sleepable_once(buf, nbytes) \84 DO_ONCE_SLEEPABLE(get_random_bytes, (buf), (nbytes))85 86#endif /* _LINUX_ONCE_H */87