1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
2 /*
3  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
4  *                         University Research and Technology
5  *                         Corporation.  All rights reserved.
6  * Copyright (c) 2004-2007 The University of Tennessee and The University
7  *                         of Tennessee Research Foundation.  All rights
8  *                         reserved.
9  * Copyright (c) 2004-2006 High Performance Computing Center Stuttgart,
10  *                         University of Stuttgart.  All rights reserved.
11  * Copyright (c) 2004-2005 The Regents of the University of California.
12  *                         All rights reserved.
13  * Copyright (c) 2007-2014 Cisco Systems, Inc.  All rights reserved.
14  * Copyright (c) 2014-2016 Research Organization for Information Science
15  *                         and Technology (RIST). All rights reserved.
16  * Copyright (c) 2015-2017 Los Alamos National Security, LLC. All rights
17  *                         reserved.
18  * $COPYRIGHT$
19  *
20  * Additional copyrights may follow
21  *
22  * $HEADER$
23  */
24 
25 #if !defined(OPAL_THREAD_USAGE_H)
26 #define OPAL_THREAD_USAGE_H
27 
28 #include "opal_config.h"
29 
30 #include "opal/sys/atomic.h"
31 #include "opal/prefetch.h"
32 
33 OPAL_DECLSPEC extern bool opal_uses_threads;
34 
35 /**
36  * Check and see if the process is using multiple threads.
37  *
38  * @retval true If the process may have more than one thread.
39  * @retval false If the process only has a single thread.
40  *
41  * The value that this function returns is influenced by:
42  *
43  * - how MPI_INIT or MPI_INIT_THREAD was invoked,
44  * - what the final MPI thread level was determined to be,
45  * - whether the OMPI or MPI libraries are multi-threaded
46  *
47  * MPI_INIT and MPI_INIT_THREAD (specifically, back-end OMPI startup
48  * functions) invoke opal_set_using_threads() to influence the value of
49  * this function, depending on their situation. Some examples:
50  *
51  * - if MPI_INIT is invoked, and the ompi components in use are
52  * single-threaded, this value will be false.
53  *
54  * - if MPI_INIT_THREAD is invoked with MPI_THREAD_MULTIPLE, we have
55  * thread support, and the final thread level is determined to be
56  * MPI_THREAD_MULTIPLE, this value will be true.
57  *
58  * - if the process is a single-threaded OMPI executable (e.g., mpicc),
59  * this value will be false.
60  *
61  * Hence, this function will return false if there is guaranteed to
62  * only be one thread in the process.  If there is even the
63  * possibility that we may have multiple threads, true will be
64  * returned.
65  */
66 #define opal_using_threads()  opal_uses_threads
67 
68 /**
69  * Set whether the process is using multiple threads or not.
70  *
71  * @param have Boolean indicating whether the process is using
72  * multiple threads or not.
73  *
74  * @retval opal_using_threads The new return value from
75  * opal_using_threads().
76  *
77  * This function is used to influence the return value of
78  * opal_using_threads().  If configure detected that we have thread
79  * support, the return value of future invocations of
80  * opal_using_threads() will be the parameter's value.  If configure
81  * detected that we have no thread support, then the retuen from
82  * opal_using_threads() will always be false.
83  */
opal_set_using_threads(bool have)84 static inline bool opal_set_using_threads(bool have)
85 {
86     opal_uses_threads = have;
87     return opal_using_threads();
88 }
89 
90 
91 // Back-ported from master (2019-05-04) as part of
92 // a16cf0e4dd6df4dea820fecedd5920df632935b8
93 typedef volatile size_t opal_atomic_size_t;
94 
95 /**
96  * Use an atomic operation for increment/decrement if opal_using_threads()
97  * indicates that threads are in use by the application or library.
98  */
99 
100 #define OPAL_THREAD_DEFINE_ATOMIC_OP(type, name, operator, suffix)      \
101 static inline type opal_thread_ ## name ## _fetch_ ## suffix (volatile type *addr, type delta) \
102 {                                                                       \
103     if (OPAL_UNLIKELY(opal_using_threads())) {                          \
104         return opal_atomic_ ## name ## _fetch_ ## suffix (addr, delta); \
105     }                                                                   \
106                                                                         \
107     *addr = *addr operator delta;                                       \
108     return *addr;                                                       \
109 }                                                                       \
110                                                                         \
111 static inline type opal_thread_fetch_ ## name ## _ ## suffix (volatile type *addr, type delta) \
112 {                                                                       \
113     if (OPAL_UNLIKELY(opal_using_threads())) {                          \
114         return opal_atomic_fetch_ ## name ## _ ## suffix (addr, delta); \
115     }                                                                   \
116                                                                         \
117     type old = *addr;                                                   \
118     *addr = old operator delta;                                         \
119     return old;                                                         \
120 }
121 
122 #define OPAL_THREAD_DEFINE_ATOMIC_COMPARE_EXCHANGE(type, addr_type, suffix)       \
123 static inline bool opal_thread_compare_exchange_strong_ ## suffix (volatile addr_type *addr, type *compare, type value) \
124 {                                                                       \
125     if (OPAL_UNLIKELY(opal_using_threads())) {                          \
126         return opal_atomic_compare_exchange_strong_ ## suffix ((volatile type *) addr, compare, value); \
127     }                                                                   \
128                                                                         \
129     if ((type) *addr == *compare) {                                     \
130         ((type *) addr)[0] = value;                                     \
131         return true;                                                    \
132     }                                                                   \
133                                                                         \
134     *compare = ((type *) addr)[0];                                      \
135                                                                         \
136     return false;                                                       \
137 }
138 
139 #define OPAL_THREAD_DEFINE_ATOMIC_SWAP(type, addr_type, suffix)         \
140 static inline type opal_thread_swap_ ## suffix (volatile addr_type *ptr, type newvalue) \
141 {                                                                       \
142     if (opal_using_threads ()) {                                        \
143         return opal_atomic_swap_ ## suffix ((volatile type *) ptr, newvalue); \
144     }                                                                   \
145                                                                         \
146     type old = ((type *) ptr)[0];                                       \
147     ((type *) ptr)[0] = newvalue;                                       \
148                                                                         \
149     return old;                                                         \
150 }
151 
152 OPAL_THREAD_DEFINE_ATOMIC_OP(int32_t, add, +, 32)
153 OPAL_THREAD_DEFINE_ATOMIC_OP(size_t, add, +, size_t)
154 OPAL_THREAD_DEFINE_ATOMIC_OP(int32_t, and, &, 32)
155 OPAL_THREAD_DEFINE_ATOMIC_OP(int32_t, or, |, 32)
156 OPAL_THREAD_DEFINE_ATOMIC_OP(int32_t, xor, ^, 32)
157 OPAL_THREAD_DEFINE_ATOMIC_OP(int32_t, sub, -, 32)
158 OPAL_THREAD_DEFINE_ATOMIC_OP(size_t, sub, -, size_t)
159 
160 OPAL_THREAD_DEFINE_ATOMIC_COMPARE_EXCHANGE(int32_t, int32_t, 32)
161 OPAL_THREAD_DEFINE_ATOMIC_COMPARE_EXCHANGE(void *, intptr_t, ptr)
162 OPAL_THREAD_DEFINE_ATOMIC_SWAP(int32_t, int32_t, 32)
163 OPAL_THREAD_DEFINE_ATOMIC_SWAP(void *, intptr_t, ptr)
164 
165 #define OPAL_THREAD_ADD_FETCH32 opal_thread_add_fetch_32
166 #define OPAL_ATOMIC_ADD_FETCH32 opal_thread_add_fetch_32
167 
168 #define OPAL_THREAD_AND_FETCH32 opal_thread_and_fetch_32
169 #define OPAL_ATOMIC_AND_FETCH32 opal_thread_and_fetch_32
170 
171 #define OPAL_THREAD_OR_FETCH32 opal_thread_or_fetch_32
172 #define OPAL_ATOMIC_OR_FETCH32 opal_thread_or_fetch_32
173 
174 #define OPAL_THREAD_XOR_FETCH32 opal_thread_xor_fetch_32
175 #define OPAL_ATOMIC_XOR_FETCH32 opal_thread_xor_fetch_32
176 
177 #define OPAL_THREAD_ADD_FETCH_SIZE_T opal_thread_add_fetch_size_t
178 #define OPAL_ATOMIC_ADD_FETCH_SIZE_T opal_thread_add_fetch_size_t
179 
180 #define OPAL_THREAD_SUB_FETCH_SIZE_T opal_thread_sub_fetch_size_t
181 #define OPAL_ATOMIC_SUB_FETCH_SIZE_T opal_thread_sub_fetch_size_t
182 
183 #define OPAL_THREAD_FETCH_ADD32 opal_thread_fetch_add_32
184 #define OPAL_ATOMIC_FETCH_ADD32 opal_thread_fetch_add_32
185 
186 #define OPAL_THREAD_FETCH_AND32 opal_thread_fetch_and_32
187 #define OPAL_ATOMIC_FETCH_AND32 opal_thread_fetch_and_32
188 
189 #define OPAL_THREAD_FETCH_OR32 opal_thread_fetch_or_32
190 #define OPAL_ATOMIC_FETCH_OR32 opal_thread_fetch_or_32
191 
192 #define OPAL_THREAD_FETCH_XOR32 opal_thread_fetch_xor_32
193 #define OPAL_ATOMIC_FETCH_XOR32 opal_thread_fetch_xor_32
194 
195 #define OPAL_THREAD_FETCH_ADD_SIZE_T opal_thread_fetch_add_size_t
196 #define OPAL_ATOMIC_FETCH_ADD_SIZE_T opal_thread_fetch_add_size_t
197 
198 #define OPAL_THREAD_FETCH_SUB_SIZE_T opal_thread_fetch_sub_size_t
199 #define OPAL_ATOMIC_FETCH_SUB_SIZE_T opal_thread_fetch_sub_size_t
200 
201 #define OPAL_THREAD_COMPARE_EXCHANGE_STRONG_32 opal_thread_compare_exchange_strong_32
202 #define OPAL_ATOMIC_COMPARE_EXCHANGE_STRONG_32 opal_thread_compare_exchange_strong_32
203 
204 #define OPAL_THREAD_COMPARE_EXCHANGE_STRONG_PTR(x, y, z) opal_thread_compare_exchange_strong_ptr ((volatile intptr_t *) x, (void *) y, (void *) z)
205 #define OPAL_ATOMIC_COMPARE_EXCHANGE_STRONG_PTR OPAL_THREAD_COMPARE_EXCHANGE_STRONG_PTR
206 
207 #define OPAL_THREAD_SWAP_32 opal_thread_swap_32
208 #define OPAL_ATOMIC_SWAP_32 opal_thread_swap_32
209 
210 #define OPAL_THREAD_SWAP_PTR(x, y) opal_thread_swap_ptr ((volatile intptr_t *) x, (void *) y)
211 #define OPAL_ATOMIC_SWAP_PTR OPAL_THREAD_SWAP_PTR
212 
213 /* define 64-bit macros is 64-bit atomic math is available */
214 #if OPAL_HAVE_ATOMIC_MATH_64
215 
216 OPAL_THREAD_DEFINE_ATOMIC_OP(int64_t, add, +, 64)
217 OPAL_THREAD_DEFINE_ATOMIC_OP(int64_t, and, &, 64)
218 OPAL_THREAD_DEFINE_ATOMIC_OP(int64_t, or, |, 64)
219 OPAL_THREAD_DEFINE_ATOMIC_OP(int64_t, xor, ^, 64)
220 OPAL_THREAD_DEFINE_ATOMIC_OP(int64_t, sub, -, 64)
221 OPAL_THREAD_DEFINE_ATOMIC_COMPARE_EXCHANGE(int64_t, int64_t, 64)
222 OPAL_THREAD_DEFINE_ATOMIC_SWAP(int64_t, int64_t, 64)
223 
224 #define OPAL_THREAD_ADD_FETCH64 opal_thread_add_fetch_64
225 #define OPAL_ATOMIC_ADD_FETCH64 opal_thread_add_fetch_64
226 
227 #define OPAL_THREAD_AND_FETCH64 opal_thread_and_fetch_64
228 #define OPAL_ATOMIC_AND_FETCH64 opal_thread_and_fetch_64
229 
230 #define OPAL_THREAD_OR_FETCH64 opal_thread_or_fetch_64
231 #define OPAL_ATOMIC_OR_FETCH64 opal_thread_or_fetch_64
232 
233 #define OPAL_THREAD_XOR_FETCH64 opal_thread_xor_fetch_64
234 #define OPAL_ATOMIC_XOR_FETCH64 opal_thread_xor_fetch_64
235 
236 #define OPAL_THREAD_FETCH_ADD64 opal_thread_fetch_add_64
237 #define OPAL_ATOMIC_FETCH_ADD64 opal_thread_fetch_add_64
238 
239 #define OPAL_THREAD_FETCH_AND64 opal_thread_fetch_and_64
240 #define OPAL_ATOMIC_FETCH_AND64 opal_thread_fetch_and_64
241 
242 #define OPAL_THREAD_FETCH_OR64 opal_thread_fetch_or_64
243 #define OPAL_ATOMIC_FETCH_OR64 opal_thread_fetch_or_64
244 
245 #define OPAL_THREAD_FETCH_XOR64 opal_thread_fetch_xor_64
246 #define OPAL_ATOMIC_FETCH_XOR64 opal_thread_fetch_xor_64
247 
248 #define OPAL_THREAD_COMPARE_EXCHANGE_STRONG_64 opal_thread_compare_exchange_strong_64
249 #define OPAL_ATOMIC_COMPARE_EXCHANGE_STRONG_64 opal_thread_compare_exchange_strong_64
250 
251 #define OPAL_THREAD_SWAP_64 opal_thread_swap_64
252 #define OPAL_ATOMIC_SWAP_64 opal_thread_swap_64
253 
254 #endif
255 
256 /* thread local storage */
257 #if OPAL_C_HAVE__THREAD_LOCAL
258 #define opal_thread_local _Thread_local
259 #define OPAL_HAVE_THREAD_LOCAL 1
260 
261 #elif OPAL_C_HAVE___THREAD /* OPAL_C_HAVE__THREAD_LOCAL */
262 #define opal_thread_local __thread
263 #define OPAL_HAVE_THREAD_LOCAL 1
264 #endif /* OPAL_C_HAVE___THREAD */
265 
266 #if !defined(OPAL_HAVE_THREAD_LOCAL)
267 #define OPAL_HAVE_THREAD_LOCAL 0
268 #endif /* !defined(OPAL_HAVE_THREAD_LOCAL) */
269 
270 #endif /* !defined(OPAL_THREAD_USAGE_H) */
271