blob: 756e557075bcb7ef522485fb08c53f5d5453ebfd [file] [log] [blame]
Jim Cownie4cc4bb42014-10-07 16:25:50 +00001/*
2 * kmp_wait_release.h -- Wait/Release implementation
Jim Cownie4cc4bb42014-10-07 16:25:50 +00003 */
4
5
6//===----------------------------------------------------------------------===//
7//
8// The LLVM Compiler Infrastructure
9//
10// This file is dual licensed under the MIT and the University of Illinois Open
11// Source Licenses. See LICENSE.txt for details.
12//
13//===----------------------------------------------------------------------===//
14
15
16#ifndef KMP_WAIT_RELEASE_H
17#define KMP_WAIT_RELEASE_H
18
19#include "kmp.h"
20#include "kmp_itt.h"
Jonathan Peyton11dc82f2016-05-05 16:15:57 +000021#include "kmp_stats.h"
Jim Cownie4cc4bb42014-10-07 16:25:50 +000022
23/*!
24@defgroup WAIT_RELEASE Wait/Release operations
25
26The definitions and functions here implement the lowest level thread
Jonathan Peyton30419822017-05-12 18:01:32 +000027synchronizations of suspending a thread and awaking it. They are used to build
28higher level operations such as barriers and fork/join.
Jim Cownie4cc4bb42014-10-07 16:25:50 +000029*/
30
31/*!
32@ingroup WAIT_RELEASE
33@{
34*/
35
Jonathan Peyton61118492016-05-20 19:03:38 +000036/*!
Jim Cownie4cc4bb42014-10-07 16:25:50 +000037 * The flag_type describes the storage used for the flag.
38 */
39enum flag_type {
Jonathan Peyton30419822017-05-12 18:01:32 +000040 flag32, /**< 32 bit flags */
41 flag64, /**< 64 bit flags */
42 flag_oncore /**< special 64-bit flag for on-core barrier (hierarchical) */
Jim Cownie4cc4bb42014-10-07 16:25:50 +000043};
44
45/*!
46 * Base class for wait/release volatile flag
47 */
Jonathan Peyton30419822017-05-12 18:01:32 +000048template <typename P> class kmp_flag {
49 volatile P
50 *loc; /**< Pointer to the flag storage that is modified by another thread
51 */
52 flag_type t; /**< "Type" of the flag in loc */
53public:
54 typedef P flag_t;
55 kmp_flag(volatile P *p, flag_type ft) : loc(p), t(ft) {}
56 /*!
57 * @result the pointer to the actual flag
58 */
59 volatile P *get() { return loc; }
60 /*!
61 * @param new_loc in set loc to point at new_loc
62 */
63 void set(volatile P *new_loc) { loc = new_loc; }
64 /*!
65 * @result the flag_type
66 */
67 flag_type get_type() { return t; }
68 // Derived classes must provide the following:
69 /*
70 kmp_info_t * get_waiter(kmp_uint32 i);
71 kmp_uint32 get_num_waiters();
72 bool done_check();
73 bool done_check_val(P old_loc);
74 bool notdone_check();
75 P internal_release();
76 void suspend(int th_gtid);
77 void resume(int th_gtid);
78 P set_sleeping();
79 P unset_sleeping();
80 bool is_sleeping();
81 bool is_any_sleeping();
82 bool is_sleeping_val(P old_loc);
83 int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin,
84 int *thread_finished
85 USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32
86 is_constrained);
87 */
Jim Cownie4cc4bb42014-10-07 16:25:50 +000088};
89
Jonathan Peyton30419822017-05-12 18:01:32 +000090/* Spin wait loop that first does pause, then yield, then sleep. A thread that
91 calls __kmp_wait_* must make certain that another thread calls __kmp_release
92 to wake it back up to prevent deadlocks! */
Jim Cownie4cc4bb42014-10-07 16:25:50 +000093template <class C>
Jonathan Peyton1a78c632016-01-11 20:28:55 +000094static inline void
Jonathan Peyton30419822017-05-12 18:01:32 +000095__kmp_wait_template(kmp_info_t *this_thr, C *flag,
96 int final_spin USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
97 // NOTE: We may not belong to a team at this point.
98 volatile typename C::flag_t *spin = flag->get();
99 kmp_uint32 spins;
100 kmp_uint32 hibernate;
101 int th_gtid;
102 int tasks_completed = FALSE;
103 int oversubscribed;
104#if !KMP_USE_MONITOR
105 kmp_uint64 poll_count;
106 kmp_uint64 hibernate_goal;
Jonathan Peytonb66d1aa2016-09-27 17:11:17 +0000107#endif
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000108
Jonathan Peyton30419822017-05-12 18:01:32 +0000109 KMP_FSYNC_SPIN_INIT(spin, NULL);
110 if (flag->done_check()) {
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000111 KMP_FSYNC_SPIN_ACQUIRED(CCAST(typename C::flag_t *, spin));
Jonathan Peyton30419822017-05-12 18:01:32 +0000112 return;
113 }
114 th_gtid = this_thr->th.th_info.ds.ds_gtid;
115 KA_TRACE(20,
116 ("__kmp_wait_sleep: T#%d waiting for flag(%p)\n", th_gtid, flag));
Jonathan Peyton11dc82f2016-05-05 16:15:57 +0000117#if KMP_STATS_ENABLED
Jonathan Peyton30419822017-05-12 18:01:32 +0000118 stats_state_e thread_state = KMP_GET_THREAD_STATE();
Jonathan Peyton11dc82f2016-05-05 16:15:57 +0000119#endif
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000120
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000121#if OMPT_SUPPORT && OMPT_BLAME
Jonathan Peyton30419822017-05-12 18:01:32 +0000122 ompt_state_t ompt_state = this_thr->th.ompt_thread_info.state;
123 if (ompt_enabled && ompt_state != ompt_state_undefined) {
124 if (ompt_state == ompt_state_idle) {
125 if (ompt_callbacks.ompt_callback(ompt_event_idle_begin)) {
126 ompt_callbacks.ompt_callback(ompt_event_idle_begin)(th_gtid + 1);
127 }
128 } else if (ompt_callbacks.ompt_callback(ompt_event_wait_barrier_begin)) {
129 KMP_DEBUG_ASSERT(ompt_state == ompt_state_wait_barrier ||
130 ompt_state == ompt_state_wait_barrier_implicit ||
131 ompt_state == ompt_state_wait_barrier_explicit);
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000132
Jonathan Peyton30419822017-05-12 18:01:32 +0000133 ompt_lw_taskteam_t *team =
134 this_thr->th.th_team->t.ompt_serialized_team_info;
135 ompt_parallel_id_t pId;
136 ompt_task_id_t tId;
137 if (team) {
138 pId = team->ompt_team_info.parallel_id;
139 tId = team->ompt_task_info.task_id;
140 } else {
141 pId = this_thr->th.th_team->t.ompt_team_info.parallel_id;
142 tId = this_thr->th.th_current_task->ompt_task_info.task_id;
143 }
144 ompt_callbacks.ompt_callback(ompt_event_wait_barrier_begin)(pId, tId);
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000145 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000146 }
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000147#endif
148
Jonathan Peyton30419822017-05-12 18:01:32 +0000149 // Setup for waiting
150 KMP_INIT_YIELD(spins);
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000151
Jonathan Peyton30419822017-05-12 18:01:32 +0000152 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
Jonathan Peytonb66d1aa2016-09-27 17:11:17 +0000153#if KMP_USE_MONITOR
Jonathan Peyton30419822017-05-12 18:01:32 +0000154// The worker threads cannot rely on the team struct existing at this point.
155// Use the bt values cached in the thread struct instead.
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000156#ifdef KMP_ADJUST_BLOCKTIME
Jonathan Peyton30419822017-05-12 18:01:32 +0000157 if (__kmp_zero_bt && !this_thr->th.th_team_bt_set)
158 // Force immediate suspend if not set by user and more threads than
159 // available procs
160 hibernate = 0;
161 else
162 hibernate = this_thr->th.th_team_bt_intervals;
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000163#else
Jonathan Peyton30419822017-05-12 18:01:32 +0000164 hibernate = this_thr->th.th_team_bt_intervals;
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000165#endif /* KMP_ADJUST_BLOCKTIME */
166
Jonathan Peyton30419822017-05-12 18:01:32 +0000167 /* If the blocktime is nonzero, we want to make sure that we spin wait for
168 the entirety of the specified #intervals, plus up to one interval more.
169 This increment make certain that this thread doesn't go to sleep too
170 soon. */
171 if (hibernate != 0)
172 hibernate++;
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000173
Jonathan Peyton30419822017-05-12 18:01:32 +0000174 // Add in the current time value.
175 hibernate += TCR_4(__kmp_global.g.g_time.dt.t_value);
176 KF_TRACE(20, ("__kmp_wait_sleep: T#%d now=%d, hibernate=%d, intervals=%d\n",
177 th_gtid, __kmp_global.g.g_time.dt.t_value, hibernate,
178 hibernate - __kmp_global.g.g_time.dt.t_value));
Jonathan Peytonb66d1aa2016-09-27 17:11:17 +0000179#else
Jonathan Peyton30419822017-05-12 18:01:32 +0000180 hibernate_goal = KMP_NOW() + this_thr->th.th_team_bt_intervals;
181 poll_count = 0;
Jonathan Peytonb66d1aa2016-09-27 17:11:17 +0000182#endif // KMP_USE_MONITOR
Jonathan Peyton30419822017-05-12 18:01:32 +0000183 }
184
185 oversubscribed = (TCR_4(__kmp_nth) > __kmp_avail_proc);
186 KMP_MB();
187
188 // Main wait spin loop
189 while (flag->notdone_check()) {
190 int in_pool;
191 kmp_task_team_t *task_team = NULL;
192 if (__kmp_tasking_mode != tskm_immediate_exec) {
193 task_team = this_thr->th.th_task_team;
194 /* If the thread's task team pointer is NULL, it means one of 3 things:
195 1) A newly-created thread is first being released by
196 __kmp_fork_barrier(), and its task team has not been set up yet.
197 2) All tasks have been executed to completion.
198 3) Tasking is off for this region. This could be because we are in a
199 serialized region (perhaps the outer one), or else tasking was manually
200 disabled (KMP_TASKING=0). */
201 if (task_team != NULL) {
202 if (TCR_SYNC_4(task_team->tt.tt_active)) {
203 if (KMP_TASKING_ENABLED(task_team))
204 flag->execute_tasks(
205 this_thr, th_gtid, final_spin,
206 &tasks_completed USE_ITT_BUILD_ARG(itt_sync_obj), 0);
207 else
208 this_thr->th.th_reap_state = KMP_SAFE_TO_REAP;
209 } else {
210 KMP_DEBUG_ASSERT(!KMP_MASTER_TID(this_thr->th.th_info.ds.ds_tid));
211 this_thr->th.th_task_team = NULL;
212 this_thr->th.th_reap_state = KMP_SAFE_TO_REAP;
213 }
214 } else {
215 this_thr->th.th_reap_state = KMP_SAFE_TO_REAP;
216 } // if
217 } // if
218
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000219 KMP_FSYNC_SPIN_PREPARE(CCAST(typename C::flag_t *, spin));
Jonathan Peyton30419822017-05-12 18:01:32 +0000220 if (TCR_4(__kmp_global.g.g_done)) {
221 if (__kmp_global.g.g_abort)
222 __kmp_abort_thread();
223 break;
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000224 }
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000225
Jonathan Peyton30419822017-05-12 18:01:32 +0000226 // If we are oversubscribed, or have waited a bit (and
227 // KMP_LIBRARY=throughput), then yield
228 KMP_YIELD(oversubscribed);
229 // TODO: Should it be number of cores instead of thread contexts? Like:
230 // KMP_YIELD(TCR_4(__kmp_nth) > __kmp_ncores);
231 // Need performance improvement data to make the change...
232 KMP_YIELD_SPIN(spins);
233 // Check if this thread was transferred from a team
234 // to the thread pool (or vice-versa) while spinning.
235 in_pool = !!TCR_4(this_thr->th.th_in_pool);
236 if (in_pool != !!this_thr->th.th_active_in_pool) {
237 if (in_pool) { // Recently transferred from team to pool
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000238 KMP_TEST_THEN_INC32(CCAST(kmp_int32 *, &__kmp_thread_pool_active_nth));
Jonathan Peyton30419822017-05-12 18:01:32 +0000239 this_thr->th.th_active_in_pool = TRUE;
240 /* Here, we cannot assert that:
241 KMP_DEBUG_ASSERT(TCR_4(__kmp_thread_pool_active_nth) <=
242 __kmp_thread_pool_nth);
243 __kmp_thread_pool_nth is inc/dec'd by the master thread while the
244 fork/join lock is held, whereas __kmp_thread_pool_active_nth is
245 inc/dec'd asynchronously by the workers. The two can get out of sync
246 for brief periods of time. */
247 } else { // Recently transferred from pool to team
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000248 KMP_TEST_THEN_DEC32(CCAST(kmp_int32 *, &__kmp_thread_pool_active_nth));
Jonathan Peyton30419822017-05-12 18:01:32 +0000249 KMP_DEBUG_ASSERT(TCR_4(__kmp_thread_pool_active_nth) >= 0);
250 this_thr->th.th_active_in_pool = FALSE;
251 }
252 }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000253
Jonathan Peyton11dc82f2016-05-05 16:15:57 +0000254#if KMP_STATS_ENABLED
Jonathan Peyton30419822017-05-12 18:01:32 +0000255 // Check if thread has been signalled to idle state
256 // This indicates that the logical "join-barrier" has finished
257 if (this_thr->th.th_stats->isIdle() &&
258 KMP_GET_THREAD_STATE() == FORK_JOIN_BARRIER) {
259 KMP_SET_THREAD_STATE(IDLE);
260 KMP_PUSH_PARTITIONED_TIMER(OMP_idle);
261 }
Jonathan Peyton11dc82f2016-05-05 16:15:57 +0000262#endif
263
Jonathan Peyton30419822017-05-12 18:01:32 +0000264 // Don't suspend if KMP_BLOCKTIME is set to "infinite"
265 if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME)
266 continue;
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000267
Jonathan Peyton30419822017-05-12 18:01:32 +0000268 // Don't suspend if there is a likelihood of new tasks being spawned.
269 if ((task_team != NULL) && TCR_4(task_team->tt.tt_found_tasks))
270 continue;
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000271
Jonathan Peytonb66d1aa2016-09-27 17:11:17 +0000272#if KMP_USE_MONITOR
Jonathan Peyton30419822017-05-12 18:01:32 +0000273 // If we have waited a bit more, fall asleep
274 if (TCR_4(__kmp_global.g.g_time.dt.t_value) < hibernate)
275 continue;
Jonathan Peytonb66d1aa2016-09-27 17:11:17 +0000276#else
Jonathan Peyton30419822017-05-12 18:01:32 +0000277 if (KMP_BLOCKING(hibernate_goal, poll_count++))
278 continue;
Jonathan Peytonb66d1aa2016-09-27 17:11:17 +0000279#endif
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000280
Jonathan Peyton30419822017-05-12 18:01:32 +0000281 KF_TRACE(50, ("__kmp_wait_sleep: T#%d suspend time reached\n", th_gtid));
282 flag->suspend(th_gtid);
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000283
Jonathan Peyton30419822017-05-12 18:01:32 +0000284 if (TCR_4(__kmp_global.g.g_done)) {
285 if (__kmp_global.g.g_abort)
286 __kmp_abort_thread();
287 break;
288 } else if (__kmp_tasking_mode != tskm_immediate_exec &&
289 this_thr->th.th_reap_state == KMP_SAFE_TO_REAP) {
290 this_thr->th.th_reap_state = KMP_NOT_SAFE_TO_REAP;
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000291 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000292 // TODO: If thread is done with work and times out, disband/free
293 }
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000294
295#if OMPT_SUPPORT && OMPT_BLAME
Jonathan Peyton30419822017-05-12 18:01:32 +0000296 if (ompt_enabled && ompt_state != ompt_state_undefined) {
297 if (ompt_state == ompt_state_idle) {
298 if (ompt_callbacks.ompt_callback(ompt_event_idle_end)) {
299 ompt_callbacks.ompt_callback(ompt_event_idle_end)(th_gtid + 1);
300 }
301 } else if (ompt_callbacks.ompt_callback(ompt_event_wait_barrier_end)) {
302 KMP_DEBUG_ASSERT(ompt_state == ompt_state_wait_barrier ||
303 ompt_state == ompt_state_wait_barrier_implicit ||
304 ompt_state == ompt_state_wait_barrier_explicit);
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000305
Jonathan Peyton30419822017-05-12 18:01:32 +0000306 ompt_lw_taskteam_t *team =
307 this_thr->th.th_team->t.ompt_serialized_team_info;
308 ompt_parallel_id_t pId;
309 ompt_task_id_t tId;
310 if (team) {
311 pId = team->ompt_team_info.parallel_id;
312 tId = team->ompt_task_info.task_id;
313 } else {
314 pId = this_thr->th.th_team->t.ompt_team_info.parallel_id;
315 tId = this_thr->th.th_current_task->ompt_task_info.task_id;
316 }
317 ompt_callbacks.ompt_callback(ompt_event_wait_barrier_end)(pId, tId);
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000318 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000319 }
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000320#endif
Jonathan Peyton11dc82f2016-05-05 16:15:57 +0000321#if KMP_STATS_ENABLED
Jonathan Peyton30419822017-05-12 18:01:32 +0000322 // If we were put into idle state, pop that off the state stack
323 if (KMP_GET_THREAD_STATE() == IDLE) {
324 KMP_POP_PARTITIONED_TIMER();
325 KMP_SET_THREAD_STATE(thread_state);
326 this_thr->th.th_stats->resetIdleFlag();
327 }
Jonathan Peyton11dc82f2016-05-05 16:15:57 +0000328#endif
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000329
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000330 KMP_FSYNC_SPIN_ACQUIRED(CCAST(typename C::flag_t *, spin));
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000331}
332
Jonathan Peyton30419822017-05-12 18:01:32 +0000333/* Release any threads specified as waiting on the flag by releasing the flag
334 and resume the waiting thread if indicated by the sleep bit(s). A thread that
335 calls __kmp_wait_template must call this function to wake up the potentially
336 sleeping thread and prevent deadlocks! */
337template <class C> static inline void __kmp_release_template(C *flag) {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000338#ifdef KMP_DEBUG
Jonathan Peyton30419822017-05-12 18:01:32 +0000339 int gtid = TCR_4(__kmp_init_gtid) ? __kmp_get_gtid() : -1;
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000340#endif
Jonathan Peyton30419822017-05-12 18:01:32 +0000341 KF_TRACE(20, ("__kmp_release: T#%d releasing flag(%x)\n", gtid, flag->get()));
342 KMP_DEBUG_ASSERT(flag->get());
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000343 KMP_FSYNC_RELEASING(CCAST(typename C::flag_t *, flag->get()));
Jonathan Peyton6cb33c62015-12-18 23:15:35 +0000344
Jonathan Peyton30419822017-05-12 18:01:32 +0000345 flag->internal_release();
Jonathan Peyton6cb33c62015-12-18 23:15:35 +0000346
Jonathan Peyton30419822017-05-12 18:01:32 +0000347 KF_TRACE(100, ("__kmp_release: T#%d set new spin=%d\n", gtid, flag->get(),
348 *(flag->get())));
Jonathan Peyton6cb33c62015-12-18 23:15:35 +0000349
Jonathan Peyton30419822017-05-12 18:01:32 +0000350 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
351 // Only need to check sleep stuff if infinite block time not set.
352 // Are *any* threads waiting on flag sleeping?
353 if (flag->is_any_sleeping()) {
354 for (unsigned int i = 0; i < flag->get_num_waiters(); ++i) {
355 // if sleeping waiter exists at i, sets current_waiter to i inside flag
356 kmp_info_t *waiter = flag->get_waiter(i);
357 if (waiter) {
358 int wait_gtid = waiter->th.th_info.ds.ds_gtid;
359 // Wake up thread if needed
360 KF_TRACE(50, ("__kmp_release: T#%d waking up thread T#%d since sleep "
361 "flag(%p) set\n",
362 gtid, wait_gtid, flag->get()));
363 flag->resume(wait_gtid); // unsets flag's current_waiter when done
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000364 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000365 }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000366 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000367 }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000368}
369
Jonathan Peyton30419822017-05-12 18:01:32 +0000370template <typename FlagType> struct flag_traits {};
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000371
Jonathan Peyton30419822017-05-12 18:01:32 +0000372template <> struct flag_traits<kmp_uint32> {
373 typedef kmp_uint32 flag_t;
374 static const flag_type t = flag32;
375 static inline flag_t tcr(flag_t f) { return TCR_4(f); }
376 static inline flag_t test_then_add4(volatile flag_t *f) {
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000377 return KMP_TEST_THEN_ADD4_32(RCAST(kmp_int32 *, CCAST(flag_t *, f)));
Jonathan Peyton30419822017-05-12 18:01:32 +0000378 }
379 static inline flag_t test_then_or(volatile flag_t *f, flag_t v) {
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000380 return KMP_TEST_THEN_OR32(CCAST(flag_t *, f), v);
Jonathan Peyton30419822017-05-12 18:01:32 +0000381 }
382 static inline flag_t test_then_and(volatile flag_t *f, flag_t v) {
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000383 return KMP_TEST_THEN_AND32(CCAST(flag_t *, f), v);
Jonathan Peyton30419822017-05-12 18:01:32 +0000384 }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000385};
386
Jonathan Peyton30419822017-05-12 18:01:32 +0000387template <> struct flag_traits<kmp_uint64> {
388 typedef kmp_uint64 flag_t;
389 static const flag_type t = flag64;
390 static inline flag_t tcr(flag_t f) { return TCR_8(f); }
391 static inline flag_t test_then_add4(volatile flag_t *f) {
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000392 return KMP_TEST_THEN_ADD4_64(RCAST(kmp_int64 *, CCAST(flag_t *, f)));
Jonathan Peyton30419822017-05-12 18:01:32 +0000393 }
394 static inline flag_t test_then_or(volatile flag_t *f, flag_t v) {
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000395 return KMP_TEST_THEN_OR64(CCAST(flag_t *, f), v);
Jonathan Peyton30419822017-05-12 18:01:32 +0000396 }
397 static inline flag_t test_then_and(volatile flag_t *f, flag_t v) {
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000398 return KMP_TEST_THEN_AND64(CCAST(flag_t *, f), v);
Jonathan Peyton30419822017-05-12 18:01:32 +0000399 }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000400};
401
Jonathan Peyton30419822017-05-12 18:01:32 +0000402template <typename FlagType> class kmp_basic_flag : public kmp_flag<FlagType> {
403 typedef flag_traits<FlagType> traits_type;
404 FlagType checker; /**< Value to compare flag to to check if flag has been
405 released. */
406 kmp_info_t
407 *waiting_threads[1]; /**< Array of threads sleeping on this thread. */
408 kmp_uint32
409 num_waiting_threads; /**< Number of threads sleeping on this thread. */
410public:
411 kmp_basic_flag(volatile FlagType *p)
412 : kmp_flag<FlagType>(p, traits_type::t), num_waiting_threads(0) {}
413 kmp_basic_flag(volatile FlagType *p, kmp_info_t *thr)
414 : kmp_flag<FlagType>(p, traits_type::t), num_waiting_threads(1) {
415 waiting_threads[0] = thr;
416 }
417 kmp_basic_flag(volatile FlagType *p, FlagType c)
418 : kmp_flag<FlagType>(p, traits_type::t), checker(c),
419 num_waiting_threads(0) {}
420 /*!
421 * param i in index into waiting_threads
422 * @result the thread that is waiting at index i
423 */
424 kmp_info_t *get_waiter(kmp_uint32 i) {
425 KMP_DEBUG_ASSERT(i < num_waiting_threads);
426 return waiting_threads[i];
427 }
428 /*!
429 * @result num_waiting_threads
430 */
431 kmp_uint32 get_num_waiters() { return num_waiting_threads; }
432 /*!
433 * @param thr in the thread which is now waiting
434 *
435 * Insert a waiting thread at index 0.
436 */
437 void set_waiter(kmp_info_t *thr) {
438 waiting_threads[0] = thr;
439 num_waiting_threads = 1;
440 }
441 /*!
442 * @result true if the flag object has been released.
443 */
444 bool done_check() { return traits_type::tcr(*(this->get())) == checker; }
445 /*!
446 * @param old_loc in old value of flag
447 * @result true if the flag's old value indicates it was released.
448 */
449 bool done_check_val(FlagType old_loc) { return old_loc == checker; }
450 /*!
451 * @result true if the flag object is not yet released.
452 * Used in __kmp_wait_template like:
453 * @code
454 * while (flag.notdone_check()) { pause(); }
455 * @endcode
456 */
457 bool notdone_check() { return traits_type::tcr(*(this->get())) != checker; }
458 /*!
459 * @result Actual flag value before release was applied.
460 * Trigger all waiting threads to run by modifying flag to release state.
461 */
462 void internal_release() {
463 (void)traits_type::test_then_add4((volatile FlagType *)this->get());
464 }
465 /*!
466 * @result Actual flag value before sleep bit(s) set.
467 * Notes that there is at least one thread sleeping on the flag by setting
468 * sleep bit(s).
469 */
470 FlagType set_sleeping() {
471 return traits_type::test_then_or((volatile FlagType *)this->get(),
472 KMP_BARRIER_SLEEP_STATE);
473 }
474 /*!
475 * @result Actual flag value before sleep bit(s) cleared.
476 * Notes that there are no longer threads sleeping on the flag by clearing
477 * sleep bit(s).
478 */
479 FlagType unset_sleeping() {
480 return traits_type::test_then_and((volatile FlagType *)this->get(),
481 ~KMP_BARRIER_SLEEP_STATE);
482 }
483 /*!
484 * @param old_loc in old value of flag
485 * Test whether there are threads sleeping on the flag's old value in old_loc.
486 */
487 bool is_sleeping_val(FlagType old_loc) {
488 return old_loc & KMP_BARRIER_SLEEP_STATE;
489 }
490 /*!
491 * Test whether there are threads sleeping on the flag.
492 */
493 bool is_sleeping() { return is_sleeping_val(*(this->get())); }
494 bool is_any_sleeping() { return is_sleeping_val(*(this->get())); }
495 kmp_uint8 *get_stolen() { return NULL; }
496 enum barrier_type get_bt() { return bs_last_barrier; }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000497};
498
499class kmp_flag_32 : public kmp_basic_flag<kmp_uint32> {
Jonathan Peyton30419822017-05-12 18:01:32 +0000500public:
501 kmp_flag_32(volatile kmp_uint32 *p) : kmp_basic_flag<kmp_uint32>(p) {}
502 kmp_flag_32(volatile kmp_uint32 *p, kmp_info_t *thr)
503 : kmp_basic_flag<kmp_uint32>(p, thr) {}
504 kmp_flag_32(volatile kmp_uint32 *p, kmp_uint32 c)
505 : kmp_basic_flag<kmp_uint32>(p, c) {}
506 void suspend(int th_gtid) { __kmp_suspend_32(th_gtid, this); }
507 void resume(int th_gtid) { __kmp_resume_32(th_gtid, this); }
508 int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin,
509 int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
510 kmp_int32 is_constrained) {
511 return __kmp_execute_tasks_32(
512 this_thr, gtid, this, final_spin,
513 thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
514 }
515 void wait(kmp_info_t *this_thr,
516 int final_spin USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
517 __kmp_wait_template(this_thr, this,
518 final_spin USE_ITT_BUILD_ARG(itt_sync_obj));
519 }
520 void release() { __kmp_release_template(this); }
521 flag_type get_ptr_type() { return flag32; }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000522};
523
524class kmp_flag_64 : public kmp_basic_flag<kmp_uint64> {
Jonathan Peyton30419822017-05-12 18:01:32 +0000525public:
526 kmp_flag_64(volatile kmp_uint64 *p) : kmp_basic_flag<kmp_uint64>(p) {}
527 kmp_flag_64(volatile kmp_uint64 *p, kmp_info_t *thr)
528 : kmp_basic_flag<kmp_uint64>(p, thr) {}
529 kmp_flag_64(volatile kmp_uint64 *p, kmp_uint64 c)
530 : kmp_basic_flag<kmp_uint64>(p, c) {}
531 void suspend(int th_gtid) { __kmp_suspend_64(th_gtid, this); }
532 void resume(int th_gtid) { __kmp_resume_64(th_gtid, this); }
533 int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin,
534 int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
535 kmp_int32 is_constrained) {
536 return __kmp_execute_tasks_64(
537 this_thr, gtid, this, final_spin,
538 thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
539 }
540 void wait(kmp_info_t *this_thr,
541 int final_spin USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
542 __kmp_wait_template(this_thr, this,
543 final_spin USE_ITT_BUILD_ARG(itt_sync_obj));
544 }
545 void release() { __kmp_release_template(this); }
546 flag_type get_ptr_type() { return flag64; }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000547};
548
549// Hierarchical 64-bit on-core barrier instantiation
550class kmp_flag_oncore : public kmp_flag<kmp_uint64> {
Jonathan Peyton30419822017-05-12 18:01:32 +0000551 kmp_uint64 checker;
552 kmp_info_t *waiting_threads[1];
553 kmp_uint32 num_waiting_threads;
554 kmp_uint32
555 offset; /**< Portion of flag that is of interest for an operation. */
556 bool flag_switch; /**< Indicates a switch in flag location. */
557 enum barrier_type bt; /**< Barrier type. */
558 kmp_info_t *this_thr; /**< Thread that may be redirected to different flag
559 location. */
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000560#if USE_ITT_BUILD
Jonathan Peyton30419822017-05-12 18:01:32 +0000561 void *
562 itt_sync_obj; /**< ITT object that must be passed to new flag location. */
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000563#endif
Jonathan Peyton30419822017-05-12 18:01:32 +0000564 unsigned char &byteref(volatile kmp_uint64 *loc, size_t offset) {
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000565 return RCAST(unsigned char *, CCAST(kmp_uint64 *, loc))[offset];
Jonathan Peyton30419822017-05-12 18:01:32 +0000566 }
567
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000568public:
Jonathan Peyton30419822017-05-12 18:01:32 +0000569 kmp_flag_oncore(volatile kmp_uint64 *p)
570 : kmp_flag<kmp_uint64>(p, flag_oncore), num_waiting_threads(0),
571 flag_switch(false) {}
572 kmp_flag_oncore(volatile kmp_uint64 *p, kmp_uint32 idx)
573 : kmp_flag<kmp_uint64>(p, flag_oncore), num_waiting_threads(0),
574 offset(idx), flag_switch(false) {}
575 kmp_flag_oncore(volatile kmp_uint64 *p, kmp_uint64 c, kmp_uint32 idx,
576 enum barrier_type bar_t, kmp_info_t *thr
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000577#if USE_ITT_BUILD
Jonathan Peyton30419822017-05-12 18:01:32 +0000578 ,
579 void *itt
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000580#endif
Jonathan Peyton30419822017-05-12 18:01:32 +0000581 )
582 : kmp_flag<kmp_uint64>(p, flag_oncore), checker(c),
583 num_waiting_threads(0), offset(idx), flag_switch(false), bt(bar_t),
584 this_thr(thr)
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000585#if USE_ITT_BUILD
Jonathan Peyton30419822017-05-12 18:01:32 +0000586 ,
587 itt_sync_obj(itt)
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000588#endif
Jonathan Peyton30419822017-05-12 18:01:32 +0000589 {
590 }
591 kmp_info_t *get_waiter(kmp_uint32 i) {
592 KMP_DEBUG_ASSERT(i < num_waiting_threads);
593 return waiting_threads[i];
594 }
595 kmp_uint32 get_num_waiters() { return num_waiting_threads; }
596 void set_waiter(kmp_info_t *thr) {
597 waiting_threads[0] = thr;
598 num_waiting_threads = 1;
599 }
600 bool done_check_val(kmp_uint64 old_loc) {
601 return byteref(&old_loc, offset) == checker;
602 }
603 bool done_check() { return done_check_val(*get()); }
604 bool notdone_check() {
605 // Calculate flag_switch
606 if (this_thr->th.th_bar[bt].bb.wait_flag == KMP_BARRIER_SWITCH_TO_OWN_FLAG)
607 flag_switch = true;
608 if (byteref(get(), offset) != 1 && !flag_switch)
609 return true;
610 else if (flag_switch) {
611 this_thr->th.th_bar[bt].bb.wait_flag = KMP_BARRIER_SWITCHING;
612 kmp_flag_64 flag(&this_thr->th.th_bar[bt].bb.b_go,
613 (kmp_uint64)KMP_BARRIER_STATE_BUMP);
614 __kmp_wait_64(this_thr, &flag, TRUE
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000615#if USE_ITT_BUILD
Jonathan Peyton30419822017-05-12 18:01:32 +0000616 ,
617 itt_sync_obj
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000618#endif
Jonathan Peyton30419822017-05-12 18:01:32 +0000619 );
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000620 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000621 return false;
622 }
623 void internal_release() {
624 if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME) {
625 byteref(get(), offset) = 1;
626 } else {
627 kmp_uint64 mask = 0;
628 byteref(&mask, offset) = 1;
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000629 KMP_TEST_THEN_OR64(CCAST(kmp_uint64 *, get()), mask);
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000630 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000631 }
632 kmp_uint64 set_sleeping() {
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000633 return KMP_TEST_THEN_OR64(CCAST(kmp_uint64 *, get()),
Jonathan Peyton30419822017-05-12 18:01:32 +0000634 KMP_BARRIER_SLEEP_STATE);
635 }
636 kmp_uint64 unset_sleeping() {
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000637 return KMP_TEST_THEN_AND64(CCAST(kmp_uint64 *, get()),
Jonathan Peyton30419822017-05-12 18:01:32 +0000638 ~KMP_BARRIER_SLEEP_STATE);
639 }
640 bool is_sleeping_val(kmp_uint64 old_loc) {
641 return old_loc & KMP_BARRIER_SLEEP_STATE;
642 }
643 bool is_sleeping() { return is_sleeping_val(*get()); }
644 bool is_any_sleeping() { return is_sleeping_val(*get()); }
645 void wait(kmp_info_t *this_thr, int final_spin) {
646 __kmp_wait_template<kmp_flag_oncore>(
647 this_thr, this, final_spin USE_ITT_BUILD_ARG(itt_sync_obj));
648 }
649 void release() { __kmp_release_template(this); }
650 void suspend(int th_gtid) { __kmp_suspend_oncore(th_gtid, this); }
651 void resume(int th_gtid) { __kmp_resume_oncore(th_gtid, this); }
652 int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin,
653 int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
654 kmp_int32 is_constrained) {
655 return __kmp_execute_tasks_oncore(
656 this_thr, gtid, this, final_spin,
657 thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
658 }
659 kmp_uint8 *get_stolen() { return NULL; }
660 enum barrier_type get_bt() { return bt; }
661 flag_type get_ptr_type() { return flag_oncore; }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000662};
663
Jonathan Peyton30419822017-05-12 18:01:32 +0000664// Used to wake up threads, volatile void* flag is usually the th_sleep_loc
665// associated with int gtid.
Jonathan Peyton11dc82f2016-05-05 16:15:57 +0000666static inline void __kmp_null_resume_wrapper(int gtid, volatile void *flag) {
Jonathan Peyton30419822017-05-12 18:01:32 +0000667 if (!flag)
668 return;
Hal Finkel55acbf82016-05-12 00:54:08 +0000669
Andrey Churbanovc47afcd2017-07-03 11:24:08 +0000670 switch (RCAST(kmp_flag_64 *, CCAST(void *, flag))->get_type()) {
Jonathan Peyton30419822017-05-12 18:01:32 +0000671 case flag32:
672 __kmp_resume_32(gtid, NULL);
673 break;
674 case flag64:
675 __kmp_resume_64(gtid, NULL);
676 break;
677 case flag_oncore:
678 __kmp_resume_oncore(gtid, NULL);
679 break;
680 }
Jonathan Peyton11dc82f2016-05-05 16:15:57 +0000681}
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000682
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000683/*!
684@}
685*/
686
687#endif // KMP_WAIT_RELEASE_H