Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
46234253 HFS |
2 | #ifndef _LINUX_ONCE_H |
3 | #define _LINUX_ONCE_H | |
4 | ||
5 | #include <linux/types.h> | |
6 | #include <linux/jump_label.h> | |
7 | ||
c90aeb94 | 8 | bool __do_once_start(bool *done, unsigned long *flags); |
cf4c950b | 9 | void __do_once_done(bool *done, struct static_key_true *once_key, |
c90aeb94 | 10 | unsigned long *flags); |
46234253 | 11 | |
c90aeb94 HFS |
12 | /* Call a function exactly once. The idea of DO_ONCE() is to perform |
13 | * a function call such as initialization of random seeds, etc, only | |
14 | * once, where DO_ONCE() can live in the fast-path. After @func has | |
15 | * been called with the passed arguments, the static key will patch | |
16 | * out the condition into a nop. DO_ONCE() guarantees type safety of | |
17 | * arguments! | |
18 | * | |
19 | * Not that the following is not equivalent ... | |
20 | * | |
21 | * DO_ONCE(func, arg); | |
22 | * DO_ONCE(func, arg); | |
23 | * | |
24 | * ... to this version: | |
25 | * | |
26 | * void foo(void) | |
27 | * { | |
28 | * DO_ONCE(func, arg); | |
29 | * } | |
30 | * | |
31 | * foo(); | |
32 | * foo(); | |
33 | * | |
34 | * In case the one-time invocation could be triggered from multiple | |
35 | * places, then a common helper function must be defined, so that only | |
36 | * a single static key will be placed there! | |
37 | */ | |
38 | #define DO_ONCE(func, ...) \ | |
39 | ({ \ | |
40 | bool ___ret = false; \ | |
41 | static bool ___done = false; \ | |
cf4c950b EB |
42 | static DEFINE_STATIC_KEY_TRUE(___once_key); \ |
43 | if (static_branch_unlikely(&___once_key)) { \ | |
c90aeb94 HFS |
44 | unsigned long ___flags; \ |
45 | ___ret = __do_once_start(&___done, &___flags); \ | |
46 | if (unlikely(___ret)) { \ | |
47 | func(__VA_ARGS__); \ | |
48 | __do_once_done(&___done, &___once_key, \ | |
49 | &___flags); \ | |
50 | } \ | |
51 | } \ | |
52 | ___ret; \ | |
46234253 HFS |
53 | }) |
54 | ||
c90aeb94 HFS |
55 | #define get_random_once(buf, nbytes) \ |
56 | DO_ONCE(get_random_bytes, (buf), (nbytes)) | |
da9ba564 JD |
57 | #define get_random_once_wait(buf, nbytes) \ |
58 | DO_ONCE(get_random_bytes_wait, (buf), (nbytes)) \ | |
c90aeb94 | 59 | |
46234253 | 60 | #endif /* _LINUX_ONCE_H */ |