blob: a277fbf2725b9766536bc5e105a074523b90c9da [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
27synchronizations of suspending a thread and awaking it. They are used
28to build higher level operations such as barriers and fork/join.
29*/
30
31/*!
32@ingroup WAIT_RELEASE
33@{
34*/
35
36/*!
37 * The flag_type describes the storage used for the flag.
38 */
39enum flag_type {
40 flag32, /**< 32 bit flags */
41 flag64, /**< 64 bit flags */
42 flag_oncore /**< special 64-bit flag for on-core barrier (hierarchical) */
43};
44
45/*!
46 * Base class for wait/release volatile flag
47 */
48template <typename P>
49class kmp_flag {
50 volatile P * loc; /**< Pointer to the flag storage that is modified by another thread */
51 flag_type t; /**< "Type" of the flag in loc */
52 public:
53 typedef P flag_t;
54 kmp_flag(volatile P *p, flag_type ft) : loc(p), t(ft) {}
55 /*!
56 * @result the pointer to the actual flag
57 */
58 volatile P * get() { return loc; }
59 /*!
Jonathan Peytona0e159f2015-10-08 18:23:38 +000060 * @param new_loc in set loc to point at new_loc
61 */
62 void set(volatile P *new_loc) { loc = new_loc; }
63 /*!
Jim Cownie4cc4bb42014-10-07 16:25:50 +000064 * @result the flag_type
65 */
66 flag_type get_type() { return t; }
67 // Derived classes must provide the following:
68 /*
69 kmp_info_t * get_waiter(kmp_uint32 i);
70 kmp_uint32 get_num_waiters();
71 bool done_check();
72 bool done_check_val(P old_loc);
73 bool notdone_check();
74 P internal_release();
Jonathan Peytona0e159f2015-10-08 18:23:38 +000075 void suspend(int th_gtid);
76 void resume(int th_gtid);
Jim Cownie4cc4bb42014-10-07 16:25:50 +000077 P set_sleeping();
78 P unset_sleeping();
79 bool is_sleeping();
Jonathan Peytona0e159f2015-10-08 18:23:38 +000080 bool is_any_sleeping();
Jim Cownie4cc4bb42014-10-07 16:25:50 +000081 bool is_sleeping_val(P old_loc);
Jonathan Peytona0e159f2015-10-08 18:23:38 +000082 int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin, int *thread_finished
83 USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained);
Jim Cownie4cc4bb42014-10-07 16:25:50 +000084 */
85};
86
87/* Spin wait loop that first does pause, then yield, then sleep. A thread that calls __kmp_wait_*
88 must make certain that another thread calls __kmp_release to wake it back up to prevent deadlocks! */
89template <class C>
Jonathan Peyton1a78c632016-01-11 20:28:55 +000090static inline void
91__kmp_wait_template(kmp_info_t *this_thr, C *flag, int final_spin
92 USE_ITT_BUILD_ARG(void * itt_sync_obj) )
Jim Cownie4cc4bb42014-10-07 16:25:50 +000093{
94 // NOTE: We may not belong to a team at this point.
95 volatile typename C::flag_t *spin = flag->get();
96 kmp_uint32 spins;
97 kmp_uint32 hibernate;
98 int th_gtid;
99 int tasks_completed = FALSE;
100
101 KMP_FSYNC_SPIN_INIT(spin, NULL);
102 if (flag->done_check()) {
103 KMP_FSYNC_SPIN_ACQUIRED(spin);
104 return;
105 }
106 th_gtid = this_thr->th.th_info.ds.ds_gtid;
107 KA_TRACE(20, ("__kmp_wait_sleep: T#%d waiting for flag(%p)\n", th_gtid, flag));
Jonathan Peyton11dc82f2016-05-05 16:15:57 +0000108#if KMP_STATS_ENABLED
109 stats_state_e thread_state = KMP_GET_THREAD_STATE();
110#endif
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000111
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000112#if OMPT_SUPPORT && OMPT_BLAME
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000113 ompt_state_t ompt_state = this_thr->th.ompt_thread_info.state;
Jonathan Peytonb68a85d2015-09-21 18:11:22 +0000114 if (ompt_enabled &&
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000115 ompt_state != ompt_state_undefined) {
116 if (ompt_state == ompt_state_idle) {
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000117 if (ompt_callbacks.ompt_callback(ompt_event_idle_begin)) {
118 ompt_callbacks.ompt_callback(ompt_event_idle_begin)(th_gtid + 1);
119 }
120 } else if (ompt_callbacks.ompt_callback(ompt_event_wait_barrier_begin)) {
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000121 KMP_DEBUG_ASSERT(ompt_state == ompt_state_wait_barrier ||
122 ompt_state == ompt_state_wait_barrier_implicit ||
123 ompt_state == ompt_state_wait_barrier_explicit);
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000124
125 ompt_lw_taskteam_t* team = this_thr->th.th_team->t.ompt_serialized_team_info;
126 ompt_parallel_id_t pId;
127 ompt_task_id_t tId;
128 if (team){
129 pId = team->ompt_team_info.parallel_id;
130 tId = team->ompt_task_info.task_id;
131 } else {
132 pId = this_thr->th.th_team->t.ompt_team_info.parallel_id;
133 tId = this_thr->th.th_current_task->ompt_task_info.task_id;
134 }
135 ompt_callbacks.ompt_callback(ompt_event_wait_barrier_begin)(pId, tId);
136 }
137 }
138#endif
139
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000140 // Setup for waiting
141 KMP_INIT_YIELD(spins);
142
143 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
144 // The worker threads cannot rely on the team struct existing at this point.
145 // Use the bt values cached in the thread struct instead.
146#ifdef KMP_ADJUST_BLOCKTIME
147 if (__kmp_zero_bt && !this_thr->th.th_team_bt_set)
148 // Force immediate suspend if not set by user and more threads than available procs
149 hibernate = 0;
150 else
151 hibernate = this_thr->th.th_team_bt_intervals;
152#else
153 hibernate = this_thr->th.th_team_bt_intervals;
154#endif /* KMP_ADJUST_BLOCKTIME */
155
156 /* If the blocktime is nonzero, we want to make sure that we spin wait for the entirety
157 of the specified #intervals, plus up to one interval more. This increment make
158 certain that this thread doesn't go to sleep too soon. */
159 if (hibernate != 0)
160 hibernate++;
161
162 // Add in the current time value.
163 hibernate += TCR_4(__kmp_global.g.g_time.dt.t_value);
164 KF_TRACE(20, ("__kmp_wait_sleep: T#%d now=%d, hibernate=%d, intervals=%d\n",
165 th_gtid, __kmp_global.g.g_time.dt.t_value, hibernate,
166 hibernate - __kmp_global.g.g_time.dt.t_value));
167 }
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000168
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000169 KMP_MB();
170
171 // Main wait spin loop
172 while (flag->notdone_check()) {
173 int in_pool;
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000174 kmp_task_team_t * task_team = NULL;
175 if (__kmp_tasking_mode != tskm_immediate_exec) {
176 task_team = this_thr->th.th_task_team;
Jonathan Peyton4cfe93c2016-03-29 21:08:29 +0000177 /* If the thread's task team pointer is NULL, it means one of 3 things:
178 1) A newly-created thread is first being released by __kmp_fork_barrier(), and
179 its task team has not been set up yet.
180 2) All tasks have been executed to completion.
181 3) Tasking is off for this region. This could be because we are in a serialized region
182 (perhaps the outer one), or else tasking was manually disabled (KMP_TASKING=0). */
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000183 if (task_team != NULL) {
Jonathan Peyton54127982015-11-04 21:37:48 +0000184 if (TCR_SYNC_4(task_team->tt.tt_active)) {
185 if (KMP_TASKING_ENABLED(task_team))
186 flag->execute_tasks(this_thr, th_gtid, final_spin, &tasks_completed
187 USE_ITT_BUILD_ARG(itt_sync_obj), 0);
188 }
189 else {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000190 KMP_DEBUG_ASSERT(!KMP_MASTER_TID(this_thr->th.th_info.ds.ds_tid));
Jonathan Peyton54127982015-11-04 21:37:48 +0000191 this_thr->th.th_task_team = NULL;
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000192 }
193 } // if
194 } // if
195
196 KMP_FSYNC_SPIN_PREPARE(spin);
197 if (TCR_4(__kmp_global.g.g_done)) {
198 if (__kmp_global.g.g_abort)
199 __kmp_abort_thread();
200 break;
201 }
202
203 // If we are oversubscribed, or have waited a bit (and KMP_LIBRARY=throughput), then yield
204 KMP_YIELD(TCR_4(__kmp_nth) > __kmp_avail_proc);
205 // TODO: Should it be number of cores instead of thread contexts? Like:
206 // KMP_YIELD(TCR_4(__kmp_nth) > __kmp_ncores);
207 // Need performance improvement data to make the change...
208 KMP_YIELD_SPIN(spins);
209
210 // Check if this thread was transferred from a team
211 // to the thread pool (or vice-versa) while spinning.
212 in_pool = !!TCR_4(this_thr->th.th_in_pool);
213 if (in_pool != !!this_thr->th.th_active_in_pool) {
214 if (in_pool) { // Recently transferred from team to pool
215 KMP_TEST_THEN_INC32((kmp_int32 *)&__kmp_thread_pool_active_nth);
216 this_thr->th.th_active_in_pool = TRUE;
217 /* Here, we cannot assert that:
218 KMP_DEBUG_ASSERT(TCR_4(__kmp_thread_pool_active_nth) <= __kmp_thread_pool_nth);
219 __kmp_thread_pool_nth is inc/dec'd by the master thread while the fork/join
220 lock is held, whereas __kmp_thread_pool_active_nth is inc/dec'd asynchronously
221 by the workers. The two can get out of sync for brief periods of time. */
222 }
223 else { // Recently transferred from pool to team
224 KMP_TEST_THEN_DEC32((kmp_int32 *) &__kmp_thread_pool_active_nth);
225 KMP_DEBUG_ASSERT(TCR_4(__kmp_thread_pool_active_nth) >= 0);
226 this_thr->th.th_active_in_pool = FALSE;
227 }
228 }
229
Jonathan Peyton11dc82f2016-05-05 16:15:57 +0000230#if KMP_STATS_ENABLED
231 // Check if thread has been signalled to idle state
232 // This indicates that the logical "join-barrier" has finished
233 if (this_thr->th.th_stats->isIdle() && KMP_GET_THREAD_STATE() == FORK_JOIN_BARRIER) {
234 KMP_SET_THREAD_STATE(IDLE);
235 KMP_PUSH_PARTITIONED_TIMER(OMP_idle);
236 }
237#endif
238
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000239 // Don't suspend if KMP_BLOCKTIME is set to "infinite"
240 if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME)
241 continue;
242
243 // Don't suspend if there is a likelihood of new tasks being spawned.
244 if ((task_team != NULL) && TCR_4(task_team->tt.tt_found_tasks))
245 continue;
246
247 // If we have waited a bit more, fall asleep
248 if (TCR_4(__kmp_global.g.g_time.dt.t_value) < hibernate)
249 continue;
250
251 KF_TRACE(50, ("__kmp_wait_sleep: T#%d suspend time reached\n", th_gtid));
252
253 flag->suspend(th_gtid);
254
255 if (TCR_4(__kmp_global.g.g_done)) {
256 if (__kmp_global.g.g_abort)
257 __kmp_abort_thread();
258 break;
259 }
260 // TODO: If thread is done with work and times out, disband/free
261 }
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000262
263#if OMPT_SUPPORT && OMPT_BLAME
Jonathan Peytonb68a85d2015-09-21 18:11:22 +0000264 if (ompt_enabled &&
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000265 ompt_state != ompt_state_undefined) {
266 if (ompt_state == ompt_state_idle) {
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000267 if (ompt_callbacks.ompt_callback(ompt_event_idle_end)) {
268 ompt_callbacks.ompt_callback(ompt_event_idle_end)(th_gtid + 1);
269 }
270 } else if (ompt_callbacks.ompt_callback(ompt_event_wait_barrier_end)) {
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000271 KMP_DEBUG_ASSERT(ompt_state == ompt_state_wait_barrier ||
272 ompt_state == ompt_state_wait_barrier_implicit ||
273 ompt_state == ompt_state_wait_barrier_explicit);
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000274
275 ompt_lw_taskteam_t* team = this_thr->th.th_team->t.ompt_serialized_team_info;
276 ompt_parallel_id_t pId;
277 ompt_task_id_t tId;
278 if (team){
279 pId = team->ompt_team_info.parallel_id;
280 tId = team->ompt_task_info.task_id;
281 } else {
282 pId = this_thr->th.th_team->t.ompt_team_info.parallel_id;
283 tId = this_thr->th.th_current_task->ompt_task_info.task_id;
284 }
285 ompt_callbacks.ompt_callback(ompt_event_wait_barrier_end)(pId, tId);
286 }
287 }
288#endif
Jonathan Peyton11dc82f2016-05-05 16:15:57 +0000289#if KMP_STATS_ENABLED
290 // If we were put into idle state, pop that off the state stack
291 if (KMP_GET_THREAD_STATE() == IDLE) {
292 KMP_POP_PARTITIONED_TIMER();
293 KMP_SET_THREAD_STATE(thread_state);
294 this_thr->th.th_stats->resetIdleFlag();
295 }
296#endif
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000297
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000298 KMP_FSYNC_SPIN_ACQUIRED(spin);
299}
300
301/* Release any threads specified as waiting on the flag by releasing the flag and resume the waiting thread
302 if indicated by the sleep bit(s). A thread that calls __kmp_wait_template must call this function to wake
303 up the potentially sleeping thread and prevent deadlocks! */
304template <class C>
Jonathan Peyton1a78c632016-01-11 20:28:55 +0000305static inline void
306__kmp_release_template(C *flag)
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000307{
308#ifdef KMP_DEBUG
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000309 int gtid = TCR_4(__kmp_init_gtid) ? __kmp_get_gtid() : -1;
310#endif
Jonathan Peytone03b62f2015-10-08 18:49:40 +0000311 KF_TRACE(20, ("__kmp_release: T#%d releasing flag(%x)\n", gtid, flag->get()));
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000312 KMP_DEBUG_ASSERT(flag->get());
313 KMP_FSYNC_RELEASING(flag->get());
Jonathan Peyton6cb33c62015-12-18 23:15:35 +0000314
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000315 flag->internal_release();
Jonathan Peyton6cb33c62015-12-18 23:15:35 +0000316
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000317 KF_TRACE(100, ("__kmp_release: T#%d set new spin=%d\n", gtid, flag->get(), *(flag->get())));
Jonathan Peyton6cb33c62015-12-18 23:15:35 +0000318
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000319 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
320 // Only need to check sleep stuff if infinite block time not set
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000321 if (flag->is_any_sleeping()) { // Are *any* of the threads that wait on this flag sleeping?
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000322 for (unsigned int i=0; i<flag->get_num_waiters(); ++i) {
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000323 kmp_info_t * waiter = flag->get_waiter(i); // if a sleeping waiter exists at i, sets current_waiter to i inside the flag
324 if (waiter) {
325 int wait_gtid = waiter->th.th_info.ds.ds_gtid;
326 // Wake up thread if needed
327 KF_TRACE(50, ("__kmp_release: T#%d waking up thread T#%d since sleep flag(%p) set\n",
328 gtid, wait_gtid, flag->get()));
329 flag->resume(wait_gtid); // unsets flag's current_waiter when done
330 }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000331 }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000332 }
333 }
334}
335
336template <typename FlagType>
337struct flag_traits {};
338
339template <>
340struct flag_traits<kmp_uint32> {
341 typedef kmp_uint32 flag_t;
342 static const flag_type t = flag32;
343 static inline flag_t tcr(flag_t f) { return TCR_4(f); }
344 static inline flag_t test_then_add4(volatile flag_t *f) { return KMP_TEST_THEN_ADD4_32((volatile kmp_int32 *)f); }
345 static inline flag_t test_then_or(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_OR32((volatile kmp_int32 *)f, v); }
346 static inline flag_t test_then_and(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_AND32((volatile kmp_int32 *)f, v); }
347};
348
349template <>
350struct flag_traits<kmp_uint64> {
351 typedef kmp_uint64 flag_t;
352 static const flag_type t = flag64;
353 static inline flag_t tcr(flag_t f) { return TCR_8(f); }
354 static inline flag_t test_then_add4(volatile flag_t *f) { return KMP_TEST_THEN_ADD4_64((volatile kmp_int64 *)f); }
355 static inline flag_t test_then_or(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_OR64((volatile kmp_int64 *)f, v); }
356 static inline flag_t test_then_and(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_AND64((volatile kmp_int64 *)f, v); }
357};
358
359template <typename FlagType>
360class kmp_basic_flag : public kmp_flag<FlagType> {
361 typedef flag_traits<FlagType> traits_type;
362 FlagType checker; /**< Value to compare flag to to check if flag has been released. */
363 kmp_info_t * waiting_threads[1]; /**< Array of threads sleeping on this thread. */
364 kmp_uint32 num_waiting_threads; /**< Number of threads sleeping on this thread. */
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000365 public:
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000366 kmp_basic_flag(volatile FlagType *p) : kmp_flag<FlagType>(p, traits_type::t), num_waiting_threads(0) {}
367 kmp_basic_flag(volatile FlagType *p, kmp_info_t *thr) : kmp_flag<FlagType>(p, traits_type::t), num_waiting_threads(1) {
368 waiting_threads[0] = thr;
369 }
370 kmp_basic_flag(volatile FlagType *p, FlagType c) : kmp_flag<FlagType>(p, traits_type::t), checker(c), num_waiting_threads(0) {}
371 /*!
372 * param i in index into waiting_threads
373 * @result the thread that is waiting at index i
374 */
375 kmp_info_t * get_waiter(kmp_uint32 i) {
376 KMP_DEBUG_ASSERT(i<num_waiting_threads);
377 return waiting_threads[i];
378 }
379 /*!
380 * @result num_waiting_threads
381 */
382 kmp_uint32 get_num_waiters() { return num_waiting_threads; }
383 /*!
384 * @param thr in the thread which is now waiting
385 *
386 * Insert a waiting thread at index 0.
387 */
388 void set_waiter(kmp_info_t *thr) {
389 waiting_threads[0] = thr;
390 num_waiting_threads = 1;
391 }
392 /*!
393 * @result true if the flag object has been released.
394 */
395 bool done_check() { return traits_type::tcr(*(this->get())) == checker; }
396 /*!
397 * @param old_loc in old value of flag
398 * @result true if the flag's old value indicates it was released.
399 */
400 bool done_check_val(FlagType old_loc) { return old_loc == checker; }
401 /*!
402 * @result true if the flag object is not yet released.
403 * Used in __kmp_wait_template like:
404 * @code
405 * while (flag.notdone_check()) { pause(); }
406 * @endcode
407 */
408 bool notdone_check() { return traits_type::tcr(*(this->get())) != checker; }
409 /*!
410 * @result Actual flag value before release was applied.
411 * Trigger all waiting threads to run by modifying flag to release state.
412 */
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000413 void internal_release() {
414 (void) traits_type::test_then_add4((volatile FlagType *)this->get());
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000415 }
416 /*!
417 * @result Actual flag value before sleep bit(s) set.
418 * Notes that there is at least one thread sleeping on the flag by setting sleep bit(s).
419 */
420 FlagType set_sleeping() {
421 return traits_type::test_then_or((volatile FlagType *)this->get(), KMP_BARRIER_SLEEP_STATE);
422 }
423 /*!
424 * @result Actual flag value before sleep bit(s) cleared.
425 * Notes that there are no longer threads sleeping on the flag by clearing sleep bit(s).
426 */
427 FlagType unset_sleeping() {
428 return traits_type::test_then_and((volatile FlagType *)this->get(), ~KMP_BARRIER_SLEEP_STATE);
429 }
430 /*!
431 * @param old_loc in old value of flag
432 * Test whether there are threads sleeping on the flag's old value in old_loc.
433 */
434 bool is_sleeping_val(FlagType old_loc) { return old_loc & KMP_BARRIER_SLEEP_STATE; }
435 /*!
436 * Test whether there are threads sleeping on the flag.
437 */
438 bool is_sleeping() { return is_sleeping_val(*(this->get())); }
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000439 bool is_any_sleeping() { return is_sleeping_val(*(this->get())); }
440 kmp_uint8 *get_stolen() { return NULL; }
441 enum barrier_type get_bt() { return bs_last_barrier; }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000442};
443
444class kmp_flag_32 : public kmp_basic_flag<kmp_uint32> {
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000445 public:
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000446 kmp_flag_32(volatile kmp_uint32 *p) : kmp_basic_flag<kmp_uint32>(p) {}
447 kmp_flag_32(volatile kmp_uint32 *p, kmp_info_t *thr) : kmp_basic_flag<kmp_uint32>(p, thr) {}
448 kmp_flag_32(volatile kmp_uint32 *p, kmp_uint32 c) : kmp_basic_flag<kmp_uint32>(p, c) {}
449 void suspend(int th_gtid) { __kmp_suspend_32(th_gtid, this); }
450 void resume(int th_gtid) { __kmp_resume_32(th_gtid, this); }
451 int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin, int *thread_finished
452 USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained) {
453 return __kmp_execute_tasks_32(this_thr, gtid, this, final_spin, thread_finished
454 USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
455 }
456 void wait(kmp_info_t *this_thr, int final_spin
457 USE_ITT_BUILD_ARG(void * itt_sync_obj)) {
458 __kmp_wait_template(this_thr, this, final_spin
459 USE_ITT_BUILD_ARG(itt_sync_obj));
460 }
461 void release() { __kmp_release_template(this); }
Jonathan Peyton3f5dfc22015-11-09 16:31:51 +0000462 flag_type get_ptr_type() { return flag32; }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000463};
464
465class kmp_flag_64 : public kmp_basic_flag<kmp_uint64> {
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000466 public:
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000467 kmp_flag_64(volatile kmp_uint64 *p) : kmp_basic_flag<kmp_uint64>(p) {}
468 kmp_flag_64(volatile kmp_uint64 *p, kmp_info_t *thr) : kmp_basic_flag<kmp_uint64>(p, thr) {}
469 kmp_flag_64(volatile kmp_uint64 *p, kmp_uint64 c) : kmp_basic_flag<kmp_uint64>(p, c) {}
470 void suspend(int th_gtid) { __kmp_suspend_64(th_gtid, this); }
471 void resume(int th_gtid) { __kmp_resume_64(th_gtid, this); }
472 int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin, int *thread_finished
473 USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained) {
474 return __kmp_execute_tasks_64(this_thr, gtid, this, final_spin, thread_finished
475 USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
476 }
477 void wait(kmp_info_t *this_thr, int final_spin
478 USE_ITT_BUILD_ARG(void * itt_sync_obj)) {
479 __kmp_wait_template(this_thr, this, final_spin
480 USE_ITT_BUILD_ARG(itt_sync_obj));
481 }
482 void release() { __kmp_release_template(this); }
Jonathan Peyton3f5dfc22015-11-09 16:31:51 +0000483 flag_type get_ptr_type() { return flag64; }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000484};
485
486// Hierarchical 64-bit on-core barrier instantiation
487class kmp_flag_oncore : public kmp_flag<kmp_uint64> {
488 kmp_uint64 checker;
489 kmp_info_t * waiting_threads[1];
490 kmp_uint32 num_waiting_threads;
491 kmp_uint32 offset; /**< Portion of flag that is of interest for an operation. */
492 bool flag_switch; /**< Indicates a switch in flag location. */
493 enum barrier_type bt; /**< Barrier type. */
494 kmp_info_t * this_thr; /**< Thread that may be redirected to different flag location. */
495#if USE_ITT_BUILD
496 void *itt_sync_obj; /**< ITT object that must be passed to new flag location. */
497#endif
Jonathan Peyton1e7a1dd2015-06-04 17:29:13 +0000498 unsigned char& byteref(volatile kmp_uint64* loc, size_t offset) { return ((unsigned char *)loc)[offset]; }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000499public:
500 kmp_flag_oncore(volatile kmp_uint64 *p)
501 : kmp_flag<kmp_uint64>(p, flag_oncore), num_waiting_threads(0), flag_switch(false) {}
502 kmp_flag_oncore(volatile kmp_uint64 *p, kmp_uint32 idx)
Jonathan Peytonc98d0302015-06-03 17:26:47 +0000503 : kmp_flag<kmp_uint64>(p, flag_oncore), num_waiting_threads(0), offset(idx), flag_switch(false) {}
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000504 kmp_flag_oncore(volatile kmp_uint64 *p, kmp_uint64 c, kmp_uint32 idx, enum barrier_type bar_t,
505 kmp_info_t * thr
506#if USE_ITT_BUILD
507 , void *itt
508#endif
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000509 )
Jonathan Peytonc98d0302015-06-03 17:26:47 +0000510 : kmp_flag<kmp_uint64>(p, flag_oncore), checker(c), num_waiting_threads(0), offset(idx),
511 flag_switch(false), bt(bar_t), this_thr(thr)
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000512#if USE_ITT_BUILD
513 , itt_sync_obj(itt)
514#endif
Jonathan Peytonc98d0302015-06-03 17:26:47 +0000515 {}
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000516 kmp_info_t * get_waiter(kmp_uint32 i) {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000517 KMP_DEBUG_ASSERT(i<num_waiting_threads);
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000518 return waiting_threads[i];
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000519 }
520 kmp_uint32 get_num_waiters() { return num_waiting_threads; }
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000521 void set_waiter(kmp_info_t *thr) {
522 waiting_threads[0] = thr;
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000523 num_waiting_threads = 1;
524 }
525 bool done_check_val(kmp_uint64 old_loc) { return byteref(&old_loc,offset) == checker; }
526 bool done_check() { return done_check_val(*get()); }
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000527 bool notdone_check() {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000528 // Calculate flag_switch
529 if (this_thr->th.th_bar[bt].bb.wait_flag == KMP_BARRIER_SWITCH_TO_OWN_FLAG)
530 flag_switch = true;
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000531 if (byteref(get(),offset) != 1 && !flag_switch)
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000532 return true;
533 else if (flag_switch) {
534 this_thr->th.th_bar[bt].bb.wait_flag = KMP_BARRIER_SWITCHING;
535 kmp_flag_64 flag(&this_thr->th.th_bar[bt].bb.b_go, (kmp_uint64)KMP_BARRIER_STATE_BUMP);
536 __kmp_wait_64(this_thr, &flag, TRUE
537#if USE_ITT_BUILD
538 , itt_sync_obj
539#endif
540 );
541 }
542 return false;
543 }
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000544 void internal_release() {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000545 if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME) {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000546 byteref(get(),offset) = 1;
547 }
548 else {
549 kmp_uint64 mask=0;
550 byteref(&mask,offset) = 1;
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000551 (void) KMP_TEST_THEN_OR64((volatile kmp_int64 *)get(), mask);
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000552 }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000553 }
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000554 kmp_uint64 set_sleeping() {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000555 return KMP_TEST_THEN_OR64((kmp_int64 volatile *)get(), KMP_BARRIER_SLEEP_STATE);
556 }
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000557 kmp_uint64 unset_sleeping() {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000558 return KMP_TEST_THEN_AND64((kmp_int64 volatile *)get(), ~KMP_BARRIER_SLEEP_STATE);
559 }
560 bool is_sleeping_val(kmp_uint64 old_loc) { return old_loc & KMP_BARRIER_SLEEP_STATE; }
561 bool is_sleeping() { return is_sleeping_val(*get()); }
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000562 bool is_any_sleeping() { return is_sleeping_val(*get()); }
563 void wait(kmp_info_t *this_thr, int final_spin) {
564 __kmp_wait_template<kmp_flag_oncore>(this_thr, this, final_spin
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000565 USE_ITT_BUILD_ARG(itt_sync_obj));
566 }
567 void release() { __kmp_release_template(this); }
568 void suspend(int th_gtid) { __kmp_suspend_oncore(th_gtid, this); }
569 void resume(int th_gtid) { __kmp_resume_oncore(th_gtid, this); }
570 int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin, int *thread_finished
571 USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained) {
572 return __kmp_execute_tasks_oncore(this_thr, gtid, this, final_spin, thread_finished
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000573 USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000574 }
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000575 kmp_uint8 *get_stolen() { return NULL; }
576 enum barrier_type get_bt() { return bt; }
Jonathan Peyton3f5dfc22015-11-09 16:31:51 +0000577 flag_type get_ptr_type() { return flag_oncore; }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000578};
579
Jonathan Peyton11dc82f2016-05-05 16:15:57 +0000580// Used to wake up threads, volatile void* flag is usually the th_sleep_loc associated
581// with int gtid.
582static inline void __kmp_null_resume_wrapper(int gtid, volatile void *flag) {
583 switch (((kmp_flag_64 *)flag)->get_type()) {
584 case flag32: __kmp_resume_32(gtid, NULL); break;
585 case flag64: __kmp_resume_64(gtid, NULL); break;
586 case flag_oncore: __kmp_resume_oncore(gtid, NULL); break;
587 }
588}
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000589
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000590/*!
591@}
592*/
593
594#endif // KMP_WAIT_RELEASE_H