blob: 2f7048cddd61ce343952d71e2548b7cfcc4f98a0 [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"
21
22/*!
23@defgroup WAIT_RELEASE Wait/Release operations
24
25The definitions and functions here implement the lowest level thread
26synchronizations of suspending a thread and awaking it. They are used
27to build higher level operations such as barriers and fork/join.
28*/
29
30/*!
31@ingroup WAIT_RELEASE
32@{
33*/
34
35/*!
36 * The flag_type describes the storage used for the flag.
37 */
38enum flag_type {
39 flag32, /**< 32 bit flags */
40 flag64, /**< 64 bit flags */
41 flag_oncore /**< special 64-bit flag for on-core barrier (hierarchical) */
42};
43
44/*!
45 * Base class for wait/release volatile flag
46 */
47template <typename P>
48class kmp_flag {
49 volatile P * loc; /**< Pointer to the flag storage that is modified by another thread */
50 flag_type t; /**< "Type" of the flag in loc */
51 public:
52 typedef P flag_t;
53 kmp_flag(volatile P *p, flag_type ft) : loc(p), t(ft) {}
54 /*!
55 * @result the pointer to the actual flag
56 */
57 volatile P * get() { return loc; }
58 /*!
Jonathan Peytona0e159f2015-10-08 18:23:38 +000059 * @param new_loc in set loc to point at new_loc
60 */
61 void set(volatile P *new_loc) { loc = new_loc; }
62 /*!
Jim Cownie4cc4bb42014-10-07 16:25:50 +000063 * @result the flag_type
64 */
65 flag_type get_type() { return t; }
66 // Derived classes must provide the following:
67 /*
68 kmp_info_t * get_waiter(kmp_uint32 i);
69 kmp_uint32 get_num_waiters();
70 bool done_check();
71 bool done_check_val(P old_loc);
72 bool notdone_check();
73 P internal_release();
Jonathan Peytona0e159f2015-10-08 18:23:38 +000074 void suspend(int th_gtid);
75 void resume(int th_gtid);
Jim Cownie4cc4bb42014-10-07 16:25:50 +000076 P set_sleeping();
77 P unset_sleeping();
78 bool is_sleeping();
Jonathan Peytona0e159f2015-10-08 18:23:38 +000079 bool is_any_sleeping();
Jim Cownie4cc4bb42014-10-07 16:25:50 +000080 bool is_sleeping_val(P old_loc);
Jonathan Peytona0e159f2015-10-08 18:23:38 +000081 int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin, int *thread_finished
82 USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained);
Jim Cownie4cc4bb42014-10-07 16:25:50 +000083 */
84};
85
86/* Spin wait loop that first does pause, then yield, then sleep. A thread that calls __kmp_wait_*
87 must make certain that another thread calls __kmp_release to wake it back up to prevent deadlocks! */
88template <class C>
89static inline void __kmp_wait_template(kmp_info_t *this_thr, C *flag, int final_spin
90 USE_ITT_BUILD_ARG(void * itt_sync_obj) )
91{
92 // NOTE: We may not belong to a team at this point.
93 volatile typename C::flag_t *spin = flag->get();
94 kmp_uint32 spins;
95 kmp_uint32 hibernate;
96 int th_gtid;
97 int tasks_completed = FALSE;
98
99 KMP_FSYNC_SPIN_INIT(spin, NULL);
100 if (flag->done_check()) {
101 KMP_FSYNC_SPIN_ACQUIRED(spin);
102 return;
103 }
104 th_gtid = this_thr->th.th_info.ds.ds_gtid;
105 KA_TRACE(20, ("__kmp_wait_sleep: T#%d waiting for flag(%p)\n", th_gtid, flag));
106
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000107#if OMPT_SUPPORT && OMPT_BLAME
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000108 ompt_state_t ompt_state = this_thr->th.ompt_thread_info.state;
Jonathan Peytonb68a85d2015-09-21 18:11:22 +0000109 if (ompt_enabled &&
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000110 ompt_state != ompt_state_undefined) {
111 if (ompt_state == ompt_state_idle) {
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000112 if (ompt_callbacks.ompt_callback(ompt_event_idle_begin)) {
113 ompt_callbacks.ompt_callback(ompt_event_idle_begin)(th_gtid + 1);
114 }
115 } else if (ompt_callbacks.ompt_callback(ompt_event_wait_barrier_begin)) {
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000116 KMP_DEBUG_ASSERT(ompt_state == ompt_state_wait_barrier ||
117 ompt_state == ompt_state_wait_barrier_implicit ||
118 ompt_state == ompt_state_wait_barrier_explicit);
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000119
120 ompt_lw_taskteam_t* team = this_thr->th.th_team->t.ompt_serialized_team_info;
121 ompt_parallel_id_t pId;
122 ompt_task_id_t tId;
123 if (team){
124 pId = team->ompt_team_info.parallel_id;
125 tId = team->ompt_task_info.task_id;
126 } else {
127 pId = this_thr->th.th_team->t.ompt_team_info.parallel_id;
128 tId = this_thr->th.th_current_task->ompt_task_info.task_id;
129 }
130 ompt_callbacks.ompt_callback(ompt_event_wait_barrier_begin)(pId, tId);
131 }
132 }
133#endif
134
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000135 // Setup for waiting
136 KMP_INIT_YIELD(spins);
137
138 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
139 // The worker threads cannot rely on the team struct existing at this point.
140 // Use the bt values cached in the thread struct instead.
141#ifdef KMP_ADJUST_BLOCKTIME
142 if (__kmp_zero_bt && !this_thr->th.th_team_bt_set)
143 // Force immediate suspend if not set by user and more threads than available procs
144 hibernate = 0;
145 else
146 hibernate = this_thr->th.th_team_bt_intervals;
147#else
148 hibernate = this_thr->th.th_team_bt_intervals;
149#endif /* KMP_ADJUST_BLOCKTIME */
150
151 /* If the blocktime is nonzero, we want to make sure that we spin wait for the entirety
152 of the specified #intervals, plus up to one interval more. This increment make
153 certain that this thread doesn't go to sleep too soon. */
154 if (hibernate != 0)
155 hibernate++;
156
157 // Add in the current time value.
158 hibernate += TCR_4(__kmp_global.g.g_time.dt.t_value);
159 KF_TRACE(20, ("__kmp_wait_sleep: T#%d now=%d, hibernate=%d, intervals=%d\n",
160 th_gtid, __kmp_global.g.g_time.dt.t_value, hibernate,
161 hibernate - __kmp_global.g.g_time.dt.t_value));
162 }
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000163
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000164 KMP_MB();
165
166 // Main wait spin loop
167 while (flag->notdone_check()) {
168 int in_pool;
169
170 /* If the task team is NULL, it means one of things:
171 1) A newly-created thread is first being released by __kmp_fork_barrier(), and
172 its task team has not been set up yet.
173 2) All tasks have been executed to completion, this thread has decremented the task
174 team's ref ct and possibly deallocated it, and should no longer reference it.
175 3) Tasking is off for this region. This could be because we are in a serialized region
176 (perhaps the outer one), or else tasking was manually disabled (KMP_TASKING=0). */
177 kmp_task_team_t * task_team = NULL;
178 if (__kmp_tasking_mode != tskm_immediate_exec) {
179 task_team = this_thr->th.th_task_team;
180 if (task_team != NULL) {
181 if (!TCR_SYNC_4(task_team->tt.tt_active)) {
182 KMP_DEBUG_ASSERT(!KMP_MASTER_TID(this_thr->th.th_info.ds.ds_tid));
183 __kmp_unref_task_team(task_team, this_thr);
Andrey Churbanov6d224db2015-02-10 18:37:43 +0000184 } else if (KMP_TASKING_ENABLED(task_team)) {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000185 flag->execute_tasks(this_thr, th_gtid, final_spin, &tasks_completed
186 USE_ITT_BUILD_ARG(itt_sync_obj), 0);
187 }
188 } // if
189 } // if
190
191 KMP_FSYNC_SPIN_PREPARE(spin);
192 if (TCR_4(__kmp_global.g.g_done)) {
193 if (__kmp_global.g.g_abort)
194 __kmp_abort_thread();
195 break;
196 }
197
198 // If we are oversubscribed, or have waited a bit (and KMP_LIBRARY=throughput), then yield
199 KMP_YIELD(TCR_4(__kmp_nth) > __kmp_avail_proc);
200 // TODO: Should it be number of cores instead of thread contexts? Like:
201 // KMP_YIELD(TCR_4(__kmp_nth) > __kmp_ncores);
202 // Need performance improvement data to make the change...
203 KMP_YIELD_SPIN(spins);
204
205 // Check if this thread was transferred from a team
206 // to the thread pool (or vice-versa) while spinning.
207 in_pool = !!TCR_4(this_thr->th.th_in_pool);
208 if (in_pool != !!this_thr->th.th_active_in_pool) {
209 if (in_pool) { // Recently transferred from team to pool
210 KMP_TEST_THEN_INC32((kmp_int32 *)&__kmp_thread_pool_active_nth);
211 this_thr->th.th_active_in_pool = TRUE;
212 /* Here, we cannot assert that:
213 KMP_DEBUG_ASSERT(TCR_4(__kmp_thread_pool_active_nth) <= __kmp_thread_pool_nth);
214 __kmp_thread_pool_nth is inc/dec'd by the master thread while the fork/join
215 lock is held, whereas __kmp_thread_pool_active_nth is inc/dec'd asynchronously
216 by the workers. The two can get out of sync for brief periods of time. */
217 }
218 else { // Recently transferred from pool to team
219 KMP_TEST_THEN_DEC32((kmp_int32 *) &__kmp_thread_pool_active_nth);
220 KMP_DEBUG_ASSERT(TCR_4(__kmp_thread_pool_active_nth) >= 0);
221 this_thr->th.th_active_in_pool = FALSE;
222 }
223 }
224
225 // Don't suspend if KMP_BLOCKTIME is set to "infinite"
226 if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME)
227 continue;
228
229 // Don't suspend if there is a likelihood of new tasks being spawned.
230 if ((task_team != NULL) && TCR_4(task_team->tt.tt_found_tasks))
231 continue;
232
233 // If we have waited a bit more, fall asleep
234 if (TCR_4(__kmp_global.g.g_time.dt.t_value) < hibernate)
235 continue;
236
237 KF_TRACE(50, ("__kmp_wait_sleep: T#%d suspend time reached\n", th_gtid));
238
239 flag->suspend(th_gtid);
240
241 if (TCR_4(__kmp_global.g.g_done)) {
242 if (__kmp_global.g.g_abort)
243 __kmp_abort_thread();
244 break;
245 }
246 // TODO: If thread is done with work and times out, disband/free
247 }
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000248
249#if OMPT_SUPPORT && OMPT_BLAME
Jonathan Peytonb68a85d2015-09-21 18:11:22 +0000250 if (ompt_enabled &&
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000251 ompt_state != ompt_state_undefined) {
252 if (ompt_state == ompt_state_idle) {
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000253 if (ompt_callbacks.ompt_callback(ompt_event_idle_end)) {
254 ompt_callbacks.ompt_callback(ompt_event_idle_end)(th_gtid + 1);
255 }
256 } else if (ompt_callbacks.ompt_callback(ompt_event_wait_barrier_end)) {
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000257 KMP_DEBUG_ASSERT(ompt_state == ompt_state_wait_barrier ||
258 ompt_state == ompt_state_wait_barrier_implicit ||
259 ompt_state == ompt_state_wait_barrier_explicit);
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000260
261 ompt_lw_taskteam_t* team = this_thr->th.th_team->t.ompt_serialized_team_info;
262 ompt_parallel_id_t pId;
263 ompt_task_id_t tId;
264 if (team){
265 pId = team->ompt_team_info.parallel_id;
266 tId = team->ompt_task_info.task_id;
267 } else {
268 pId = this_thr->th.th_team->t.ompt_team_info.parallel_id;
269 tId = this_thr->th.th_current_task->ompt_task_info.task_id;
270 }
271 ompt_callbacks.ompt_callback(ompt_event_wait_barrier_end)(pId, tId);
272 }
273 }
274#endif
275
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000276 KMP_FSYNC_SPIN_ACQUIRED(spin);
277}
278
279/* Release any threads specified as waiting on the flag by releasing the flag and resume the waiting thread
280 if indicated by the sleep bit(s). A thread that calls __kmp_wait_template must call this function to wake
281 up the potentially sleeping thread and prevent deadlocks! */
282template <class C>
283static inline void __kmp_release_template(C *flag)
284{
285#ifdef KMP_DEBUG
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000286 int gtid = TCR_4(__kmp_init_gtid) ? __kmp_get_gtid() : -1;
287#endif
Jonathan Peytone03b62f2015-10-08 18:49:40 +0000288 KF_TRACE(20, ("__kmp_release: T#%d releasing flag(%x)\n", gtid, flag->get()));
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000289 KMP_DEBUG_ASSERT(flag->get());
290 KMP_FSYNC_RELEASING(flag->get());
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000291
292 flag->internal_release();
293
294 KF_TRACE(100, ("__kmp_release: T#%d set new spin=%d\n", gtid, flag->get(), *(flag->get())));
295
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000296 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
297 // Only need to check sleep stuff if infinite block time not set
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000298 if (flag->is_any_sleeping()) { // Are *any* of the threads that wait on this flag sleeping?
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000299 for (unsigned int i=0; i<flag->get_num_waiters(); ++i) {
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000300 kmp_info_t * waiter = flag->get_waiter(i); // if a sleeping waiter exists at i, sets current_waiter to i inside the flag
301 if (waiter) {
302 int wait_gtid = waiter->th.th_info.ds.ds_gtid;
303 // Wake up thread if needed
304 KF_TRACE(50, ("__kmp_release: T#%d waking up thread T#%d since sleep flag(%p) set\n",
305 gtid, wait_gtid, flag->get()));
306 flag->resume(wait_gtid); // unsets flag's current_waiter when done
307 }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000308 }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000309 }
310 }
311}
312
313template <typename FlagType>
314struct flag_traits {};
315
316template <>
317struct flag_traits<kmp_uint32> {
318 typedef kmp_uint32 flag_t;
319 static const flag_type t = flag32;
320 static inline flag_t tcr(flag_t f) { return TCR_4(f); }
321 static inline flag_t test_then_add4(volatile flag_t *f) { return KMP_TEST_THEN_ADD4_32((volatile kmp_int32 *)f); }
322 static inline flag_t test_then_or(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_OR32((volatile kmp_int32 *)f, v); }
323 static inline flag_t test_then_and(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_AND32((volatile kmp_int32 *)f, v); }
324};
325
326template <>
327struct flag_traits<kmp_uint64> {
328 typedef kmp_uint64 flag_t;
329 static const flag_type t = flag64;
330 static inline flag_t tcr(flag_t f) { return TCR_8(f); }
331 static inline flag_t test_then_add4(volatile flag_t *f) { return KMP_TEST_THEN_ADD4_64((volatile kmp_int64 *)f); }
332 static inline flag_t test_then_or(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_OR64((volatile kmp_int64 *)f, v); }
333 static inline flag_t test_then_and(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_AND64((volatile kmp_int64 *)f, v); }
334};
335
336template <typename FlagType>
337class kmp_basic_flag : public kmp_flag<FlagType> {
338 typedef flag_traits<FlagType> traits_type;
339 FlagType checker; /**< Value to compare flag to to check if flag has been released. */
340 kmp_info_t * waiting_threads[1]; /**< Array of threads sleeping on this thread. */
341 kmp_uint32 num_waiting_threads; /**< Number of threads sleeping on this thread. */
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000342 public:
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000343 kmp_basic_flag(volatile FlagType *p) : kmp_flag<FlagType>(p, traits_type::t), num_waiting_threads(0) {}
344 kmp_basic_flag(volatile FlagType *p, kmp_info_t *thr) : kmp_flag<FlagType>(p, traits_type::t), num_waiting_threads(1) {
345 waiting_threads[0] = thr;
346 }
347 kmp_basic_flag(volatile FlagType *p, FlagType c) : kmp_flag<FlagType>(p, traits_type::t), checker(c), num_waiting_threads(0) {}
348 /*!
349 * param i in index into waiting_threads
350 * @result the thread that is waiting at index i
351 */
352 kmp_info_t * get_waiter(kmp_uint32 i) {
353 KMP_DEBUG_ASSERT(i<num_waiting_threads);
354 return waiting_threads[i];
355 }
356 /*!
357 * @result num_waiting_threads
358 */
359 kmp_uint32 get_num_waiters() { return num_waiting_threads; }
360 /*!
361 * @param thr in the thread which is now waiting
362 *
363 * Insert a waiting thread at index 0.
364 */
365 void set_waiter(kmp_info_t *thr) {
366 waiting_threads[0] = thr;
367 num_waiting_threads = 1;
368 }
369 /*!
370 * @result true if the flag object has been released.
371 */
372 bool done_check() { return traits_type::tcr(*(this->get())) == checker; }
373 /*!
374 * @param old_loc in old value of flag
375 * @result true if the flag's old value indicates it was released.
376 */
377 bool done_check_val(FlagType old_loc) { return old_loc == checker; }
378 /*!
379 * @result true if the flag object is not yet released.
380 * Used in __kmp_wait_template like:
381 * @code
382 * while (flag.notdone_check()) { pause(); }
383 * @endcode
384 */
385 bool notdone_check() { return traits_type::tcr(*(this->get())) != checker; }
386 /*!
387 * @result Actual flag value before release was applied.
388 * Trigger all waiting threads to run by modifying flag to release state.
389 */
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000390 void internal_release() {
391 (void) traits_type::test_then_add4((volatile FlagType *)this->get());
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000392 }
393 /*!
394 * @result Actual flag value before sleep bit(s) set.
395 * Notes that there is at least one thread sleeping on the flag by setting sleep bit(s).
396 */
397 FlagType set_sleeping() {
398 return traits_type::test_then_or((volatile FlagType *)this->get(), KMP_BARRIER_SLEEP_STATE);
399 }
400 /*!
401 * @result Actual flag value before sleep bit(s) cleared.
402 * Notes that there are no longer threads sleeping on the flag by clearing sleep bit(s).
403 */
404 FlagType unset_sleeping() {
405 return traits_type::test_then_and((volatile FlagType *)this->get(), ~KMP_BARRIER_SLEEP_STATE);
406 }
407 /*!
408 * @param old_loc in old value of flag
409 * Test whether there are threads sleeping on the flag's old value in old_loc.
410 */
411 bool is_sleeping_val(FlagType old_loc) { return old_loc & KMP_BARRIER_SLEEP_STATE; }
412 /*!
413 * Test whether there are threads sleeping on the flag.
414 */
415 bool is_sleeping() { return is_sleeping_val(*(this->get())); }
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000416 bool is_any_sleeping() { return is_sleeping_val(*(this->get())); }
417 kmp_uint8 *get_stolen() { return NULL; }
418 enum barrier_type get_bt() { return bs_last_barrier; }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000419};
420
421class kmp_flag_32 : public kmp_basic_flag<kmp_uint32> {
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000422 public:
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000423 kmp_flag_32(volatile kmp_uint32 *p) : kmp_basic_flag<kmp_uint32>(p) {}
424 kmp_flag_32(volatile kmp_uint32 *p, kmp_info_t *thr) : kmp_basic_flag<kmp_uint32>(p, thr) {}
425 kmp_flag_32(volatile kmp_uint32 *p, kmp_uint32 c) : kmp_basic_flag<kmp_uint32>(p, c) {}
426 void suspend(int th_gtid) { __kmp_suspend_32(th_gtid, this); }
427 void resume(int th_gtid) { __kmp_resume_32(th_gtid, this); }
428 int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin, int *thread_finished
429 USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained) {
430 return __kmp_execute_tasks_32(this_thr, gtid, this, final_spin, thread_finished
431 USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
432 }
433 void wait(kmp_info_t *this_thr, int final_spin
434 USE_ITT_BUILD_ARG(void * itt_sync_obj)) {
435 __kmp_wait_template(this_thr, this, final_spin
436 USE_ITT_BUILD_ARG(itt_sync_obj));
437 }
438 void release() { __kmp_release_template(this); }
439};
440
441class kmp_flag_64 : public kmp_basic_flag<kmp_uint64> {
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000442 public:
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000443 kmp_flag_64(volatile kmp_uint64 *p) : kmp_basic_flag<kmp_uint64>(p) {}
444 kmp_flag_64(volatile kmp_uint64 *p, kmp_info_t *thr) : kmp_basic_flag<kmp_uint64>(p, thr) {}
445 kmp_flag_64(volatile kmp_uint64 *p, kmp_uint64 c) : kmp_basic_flag<kmp_uint64>(p, c) {}
446 void suspend(int th_gtid) { __kmp_suspend_64(th_gtid, this); }
447 void resume(int th_gtid) { __kmp_resume_64(th_gtid, this); }
448 int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin, int *thread_finished
449 USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained) {
450 return __kmp_execute_tasks_64(this_thr, gtid, this, final_spin, thread_finished
451 USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
452 }
453 void wait(kmp_info_t *this_thr, int final_spin
454 USE_ITT_BUILD_ARG(void * itt_sync_obj)) {
455 __kmp_wait_template(this_thr, this, final_spin
456 USE_ITT_BUILD_ARG(itt_sync_obj));
457 }
458 void release() { __kmp_release_template(this); }
459};
460
461// Hierarchical 64-bit on-core barrier instantiation
462class kmp_flag_oncore : public kmp_flag<kmp_uint64> {
463 kmp_uint64 checker;
464 kmp_info_t * waiting_threads[1];
465 kmp_uint32 num_waiting_threads;
466 kmp_uint32 offset; /**< Portion of flag that is of interest for an operation. */
467 bool flag_switch; /**< Indicates a switch in flag location. */
468 enum barrier_type bt; /**< Barrier type. */
469 kmp_info_t * this_thr; /**< Thread that may be redirected to different flag location. */
470#if USE_ITT_BUILD
471 void *itt_sync_obj; /**< ITT object that must be passed to new flag location. */
472#endif
Jonathan Peyton1e7a1dd2015-06-04 17:29:13 +0000473 unsigned char& byteref(volatile kmp_uint64* loc, size_t offset) { return ((unsigned char *)loc)[offset]; }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000474public:
475 kmp_flag_oncore(volatile kmp_uint64 *p)
476 : kmp_flag<kmp_uint64>(p, flag_oncore), num_waiting_threads(0), flag_switch(false) {}
477 kmp_flag_oncore(volatile kmp_uint64 *p, kmp_uint32 idx)
Jonathan Peytonc98d0302015-06-03 17:26:47 +0000478 : kmp_flag<kmp_uint64>(p, flag_oncore), num_waiting_threads(0), offset(idx), flag_switch(false) {}
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000479 kmp_flag_oncore(volatile kmp_uint64 *p, kmp_uint64 c, kmp_uint32 idx, enum barrier_type bar_t,
480 kmp_info_t * thr
481#if USE_ITT_BUILD
482 , void *itt
483#endif
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000484 )
Jonathan Peytonc98d0302015-06-03 17:26:47 +0000485 : kmp_flag<kmp_uint64>(p, flag_oncore), checker(c), num_waiting_threads(0), offset(idx),
486 flag_switch(false), bt(bar_t), this_thr(thr)
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000487#if USE_ITT_BUILD
488 , itt_sync_obj(itt)
489#endif
Jonathan Peytonc98d0302015-06-03 17:26:47 +0000490 {}
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000491 kmp_info_t * get_waiter(kmp_uint32 i) {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000492 KMP_DEBUG_ASSERT(i<num_waiting_threads);
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000493 return waiting_threads[i];
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000494 }
495 kmp_uint32 get_num_waiters() { return num_waiting_threads; }
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000496 void set_waiter(kmp_info_t *thr) {
497 waiting_threads[0] = thr;
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000498 num_waiting_threads = 1;
499 }
500 bool done_check_val(kmp_uint64 old_loc) { return byteref(&old_loc,offset) == checker; }
501 bool done_check() { return done_check_val(*get()); }
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000502 bool notdone_check() {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000503 // Calculate flag_switch
504 if (this_thr->th.th_bar[bt].bb.wait_flag == KMP_BARRIER_SWITCH_TO_OWN_FLAG)
505 flag_switch = true;
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000506 if (byteref(get(),offset) != 1 && !flag_switch)
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000507 return true;
508 else if (flag_switch) {
509 this_thr->th.th_bar[bt].bb.wait_flag = KMP_BARRIER_SWITCHING;
510 kmp_flag_64 flag(&this_thr->th.th_bar[bt].bb.b_go, (kmp_uint64)KMP_BARRIER_STATE_BUMP);
511 __kmp_wait_64(this_thr, &flag, TRUE
512#if USE_ITT_BUILD
513 , itt_sync_obj
514#endif
515 );
516 }
517 return false;
518 }
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000519 void internal_release() {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000520 if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME) {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000521 byteref(get(),offset) = 1;
522 }
523 else {
524 kmp_uint64 mask=0;
525 byteref(&mask,offset) = 1;
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000526 (void) KMP_TEST_THEN_OR64((volatile kmp_int64 *)get(), mask);
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000527 }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000528 }
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000529 kmp_uint64 set_sleeping() {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000530 return KMP_TEST_THEN_OR64((kmp_int64 volatile *)get(), KMP_BARRIER_SLEEP_STATE);
531 }
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000532 kmp_uint64 unset_sleeping() {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000533 return KMP_TEST_THEN_AND64((kmp_int64 volatile *)get(), ~KMP_BARRIER_SLEEP_STATE);
534 }
535 bool is_sleeping_val(kmp_uint64 old_loc) { return old_loc & KMP_BARRIER_SLEEP_STATE; }
536 bool is_sleeping() { return is_sleeping_val(*get()); }
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000537 bool is_any_sleeping() { return is_sleeping_val(*get()); }
538 void wait(kmp_info_t *this_thr, int final_spin) {
539 __kmp_wait_template<kmp_flag_oncore>(this_thr, this, final_spin
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000540 USE_ITT_BUILD_ARG(itt_sync_obj));
541 }
542 void release() { __kmp_release_template(this); }
543 void suspend(int th_gtid) { __kmp_suspend_oncore(th_gtid, this); }
544 void resume(int th_gtid) { __kmp_resume_oncore(th_gtid, this); }
545 int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin, int *thread_finished
546 USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained) {
547 return __kmp_execute_tasks_oncore(this_thr, gtid, this, final_spin, thread_finished
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000548 USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000549 }
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000550 kmp_uint8 *get_stolen() { return NULL; }
551 enum barrier_type get_bt() { return bt; }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000552};
553
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000554
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000555/*!
556@}
557*/
558
559#endif // KMP_WAIT_RELEASE_H