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-2016 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 /**
92 * Use an atomic operation for increment/decrement if opal_using_threads()
93 * indicates that threads are in use by the application or library.
94 */
95
96 #define OPAL_THREAD_DEFINE_ATOMIC_ADD(type, suffix) \
97 static inline type opal_thread_add_ ## suffix (volatile type *addr, type delta) \
98 { \
99 if (OPAL_UNLIKELY(opal_using_threads())) { \
100 return opal_atomic_add_ ## suffix (addr, delta); \
101 } \
102 \
103 return (*addr += delta); \
104 }
105
106 #define OPAL_THREAD_DEFINE_ATOMIC_SUB(type, suffix) \
107 static inline type opal_thread_sub_ ## suffix (volatile type *addr, type delta) \
108 { \
109 if (OPAL_UNLIKELY(opal_using_threads())) { \
110 return opal_atomic_sub_ ## suffix (addr, delta); \
111 } \
112 \
113 return (*addr -= delta); \
114 }
115
116 #define OPAL_THREAD_DEFINE_ATOMIC_CMPSET(type, addr_type, suffix) \
117 static inline bool opal_thread_cmpset_bool_ ## suffix (volatile addr_type *addr, type compare, type value) \
118 { \
119 if (OPAL_UNLIKELY(opal_using_threads())) { \
120 return opal_atomic_cmpset_ ## suffix ((volatile type *) addr, compare, value); \
121 } \
122 \
123 if ((type) *addr == compare) { \
124 ((type *) addr)[0] = value; \
125 return true; \
126 } \
127 \
128 return false; \
129 }
130
131 #define OPAL_THREAD_DEFINE_ATOMIC_SWAP(type, addr_type, suffix) \
132 static inline type opal_thread_swap_ ## suffix (volatile addr_type *ptr, type newvalue) \
133 { \
134 if (opal_using_threads ()) { \
135 return opal_atomic_swap_ ## suffix ((volatile type *) ptr, newvalue); \
136 } \
137 \
138 type old = ((type *) ptr)[0]; \
139 ((type *) ptr)[0] = newvalue; \
140 \
141 return old; \
142 }
143
144 OPAL_THREAD_DEFINE_ATOMIC_ADD(int32_t, 32)
145 OPAL_THREAD_DEFINE_ATOMIC_ADD(size_t, size_t)
146 OPAL_THREAD_DEFINE_ATOMIC_SUB(size_t, size_t)
147 OPAL_THREAD_DEFINE_ATOMIC_CMPSET(int32_t, int32_t, 32)
148 OPAL_THREAD_DEFINE_ATOMIC_CMPSET(void *, intptr_t, ptr)
149 OPAL_THREAD_DEFINE_ATOMIC_SWAP(int32_t, int32_t, 32)
150 OPAL_THREAD_DEFINE_ATOMIC_SWAP(void *, intptr_t, ptr)
151
152 #define OPAL_THREAD_ADD32 opal_thread_add_32
153 #define OPAL_ATOMIC_ADD32 opal_thread_add_32
154
155 #define OPAL_THREAD_ADD_SIZE_T opal_thread_add_size_t
156 #define OPAL_ATOMIC_ADD_SIZE_T opal_thread_add_size_t
157
158 #define OPAL_THREAD_SUB_SIZE_T opal_thread_sub_size_t
159 #define OPAL_ATOMIC_SUB_SIZE_T opal_thread_sub_size_t
160
161 #define OPAL_THREAD_CMPSET_32 opal_thread_cmpset_bool_32
162 #define OPAL_ATOMIC_CMPSET_32 opal_thread_cmpset_bool_32
163
164 #define OPAL_THREAD_CMPSET_PTR(x, y, z) opal_thread_cmpset_bool_ptr ((volatile intptr_t *) x, (void *) y, (void *) z)
165 #define OPAL_ATOMIC_CMPSET_PTR OPAL_THREAD_CMPSET_PTR
166
167 #define OPAL_THREAD_SWAP_32 opal_thread_swap_32
168 #define OPAL_ATOMIC_SWAP_32 opal_thread_swap_32
169
170 #define OPAL_THREAD_SWAP_PTR(x, y) opal_thread_swap_ptr ((volatile intptr_t *) x, (void *) y)
171 #define OPAL_ATOMIC_SWAP_PTR OPAL_THREAD_SWAP_PTR
172
173 /* define 64-bit macros is 64-bit atomic math is available */
174 #if OPAL_HAVE_ATOMIC_MATH_64
175
176 OPAL_THREAD_DEFINE_ATOMIC_ADD(int64_t, 64)
177 OPAL_THREAD_DEFINE_ATOMIC_CMPSET(int64_t, int64_t, 64)
178 OPAL_THREAD_DEFINE_ATOMIC_SWAP(int64_t, int64_t, 64)
179
180 #define OPAL_THREAD_ADD64 opal_thread_add_64
181 #define OPAL_ATOMIC_ADD64 opal_thread_add_64
182
183 #define OPAL_THREAD_CMPSET_64 opal_thread_cmpset_bool_64
184 #define OPAL_ATOMIC_CMPSET_64 opal_thread_cmpset_bool_64
185
186 #define OPAL_THREAD_SWAP_64 opal_thread_swap_64
187 #define OPAL_ATOMIC_SWAP_64 opal_thread_swap_64
188
189 #endif
190
191 #endif /* !defined(OPAL_THREAD_USAGE_H) */
192