Blame view

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