Fix a RUN_ONCE bug
[openssl.git] / include / internal / thread_once.h
1 /*
2  * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include <openssl/crypto.h>
11
12 /*
13  * DEFINE_RUN_ONCE: Define an initialiser function that should be run exactly
14  * once. It takes no arguments and returns and int result (1 for success or
15  * 0 for failure). Typical usage might be:
16  *
17  * DEFINE_RUN_ONCE(myinitfunc)
18  * {
19  *     do_some_initialisation();
20  *     if (init_is_successful())
21  *         return 1;
22  *
23  *     return 0;
24  * }
25  */
26 #define DEFINE_RUN_ONCE(init)                   \
27     static int init(void);                     \
28     int init##_ossl_ret_ = 0;                   \
29     void init##_ossl_(void)                     \
30     {                                           \
31         init##_ossl_ret_ = init();              \
32     }                                           \
33     static int init(void)
34
35 /*
36  * DECLARE_RUN_ONCE: Declare an initialiser function that should be run exactly
37  * once that has been defined in another file via DEFINE_RUN_ONCE().
38  */
39 #define DECLARE_RUN_ONCE(init)                  \
40     extern int init##_ossl_ret_;                \
41     void init##_ossl_(void);
42
43 /*
44  * DEFINE_RUN_ONCE_STATIC: Define an initialiser function that should be run
45  * exactly once. This function will be declared as static within the file. It
46  * takes no arguments and returns and int result (1 for success or 0 for
47  * failure). Typical usage might be:
48  *
49  * DEFINE_RUN_ONCE_STATIC(myinitfunc)
50  * {
51  *     do_some_initialisation();
52  *     if (init_is_successful())
53  *         return 1;
54  *
55  *     return 0;
56  * }
57  */
58 #define DEFINE_RUN_ONCE_STATIC(init)            \
59     static int init(void);                     \
60     static int init##_ossl_ret_ = 0;            \
61     static void init##_ossl_(void)              \
62     {                                           \
63         init##_ossl_ret_ = init();              \
64     }                                           \
65     static int init(void)
66
67 /*
68  * DEFINE_RUN_ONCE_STATIC_ALT: Define an alternative initialiser function. This
69  * function will be declared as static within the file. It takes no arguments
70  * and returns an int result (1 for success or 0 for failure). An alternative
71  * initialiser function is expected to be associated with a primary initialiser
72  * function defined via DEFINE_ONCE_STATIC where both functions use the same
73  * CRYPTO_ONCE object to synchronise. Where an alternative initialiser function
74  * is used only one of the primary or the alternative initialiser function will
75  * ever be called - and that function will be called exactly once. Definitition
76  * of an alternative initialiser function MUST occur AFTER the definition of the
77  * primary initialiser function.
78  *
79  * Typical usage might be:
80  *
81  * DEFINE_RUN_ONCE_STATIC(myinitfunc)
82  * {
83  *     do_some_initialisation();
84  *     if (init_is_successful())
85  *         return 1;
86  *
87  *     return 0;
88  * }
89  *
90  * DEFINE_RUN_ONCE_STATIC_ALT(myaltinitfunc, myinitfunc)
91  * {
92  *     do_some_alternative_initialisation();
93  *     if (init_is_successful())
94  *         return 1;
95  *
96  *     return 0;
97  * }
98  */
99 #define DEFINE_RUN_ONCE_STATIC_ALT(initalt, init) \
100     static int initalt(void);                     \
101     static void initalt##_ossl_(void)             \
102     {                                             \
103         init##_ossl_ret_ = initalt();             \
104     }                                             \
105     static int initalt(void)
106
107 /*
108  * RUN_ONCE - use CRYPTO_THREAD_run_once, and check if the init succeeded
109  * @once: pointer to static object of type CRYPTO_ONCE
110  * @init: function name that was previously given to DEFINE_RUN_ONCE,
111  *        DEFINE_RUN_ONCE_STATIC or DECLARE_RUN_ONCE.  This function
112  *        must return 1 for success or 0 for failure.
113  *
114  * The return value is 1 on success (*) or 0 in case of error.
115  *
116  * (*) by convention, since the init function must return 1 on success.
117  */
118 #define RUN_ONCE(once, init)                                            \
119     (CRYPTO_THREAD_run_once(once, init##_ossl_) ? init##_ossl_ret_ : 0)
120
121 /*
122  * RUN_ONCE_ALT - use CRYPTO_THREAD_run_once, to run an alternative initialiser
123  *                function and check if that initialisation succeeded
124  * @once:    pointer to static object of type CRYPTO_ONCE
125  * @initalt: alternative initialiser function name that was previously given to
126  *           DEFINE_RUN_ONCE_STATIC_ALT.  This function must return 1 for
127  *           success or 0 for failure.
128  * @init:    primary initialiser function name that was previously given to
129  *           DEFINE_RUN_ONCE_STATIC.  This function must return 1 for success or
130  *           0 for failure.
131  *
132  * The return value is 1 on success (*) or 0 in case of error.
133  *
134  * (*) by convention, since the init function must return 1 on success.
135  */
136 #define RUN_ONCE_ALT(once, initalt, init)                               \
137     (CRYPTO_THREAD_run_once(once, initalt##_ossl_) ? init##_ossl_ret_ : 0)