blob: 92db155eb5acc343c7e668f24f72ab83099c5c05 [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) {
Jonathan Peyton54127982015-11-04 21:37:48 +0000181 if (TCR_SYNC_4(task_team->tt.tt_active)) {
182 if (KMP_TASKING_ENABLED(task_team))
183 flag->execute_tasks(this_thr, th_gtid, final_spin, &tasks_completed
184 USE_ITT_BUILD_ARG(itt_sync_obj), 0);
185 }
186 else {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000187 KMP_DEBUG_ASSERT(!KMP_MASTER_TID(this_thr->th.th_info.ds.ds_tid));
Jonathan Peyton54127982015-11-04 21:37:48 +0000188 this_thr->th.th_task_team = NULL;
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000189 }
190 } // if
191 } // if
192
193 KMP_FSYNC_SPIN_PREPARE(spin);
194 if (TCR_4(__kmp_global.g.g_done)) {
195 if (__kmp_global.g.g_abort)
196 __kmp_abort_thread();
197 break;
198 }
199
200 // If we are oversubscribed, or have waited a bit (and KMP_LIBRARY=throughput), then yield
201 KMP_YIELD(TCR_4(__kmp_nth) > __kmp_avail_proc);
202 // TODO: Should it be number of cores instead of thread contexts? Like:
203 // KMP_YIELD(TCR_4(__kmp_nth) > __kmp_ncores);
204 // Need performance improvement data to make the change...
205 KMP_YIELD_SPIN(spins);
206
207 // Check if this thread was transferred from a team
208 // to the thread pool (or vice-versa) while spinning.
209 in_pool = !!TCR_4(this_thr->th.th_in_pool);
210 if (in_pool != !!this_thr->th.th_active_in_pool) {
211 if (in_pool) { // Recently transferred from team to pool
212 KMP_TEST_THEN_INC32((kmp_int32 *)&__kmp_thread_pool_active_nth);
213 this_thr->th.th_active_in_pool = TRUE;
214 /* Here, we cannot assert that:
215 KMP_DEBUG_ASSERT(TCR_4(__kmp_thread_pool_active_nth) <= __kmp_thread_pool_nth);
216 __kmp_thread_pool_nth is inc/dec'd by the master thread while the fork/join
217 lock is held, whereas __kmp_thread_pool_active_nth is inc/dec'd asynchronously
218 by the workers. The two can get out of sync for brief periods of time. */
219 }
220 else { // Recently transferred from pool to team
221 KMP_TEST_THEN_DEC32((kmp_int32 *) &__kmp_thread_pool_active_nth);
222 KMP_DEBUG_ASSERT(TCR_4(__kmp_thread_pool_active_nth) >= 0);
223 this_thr->th.th_active_in_pool = FALSE;
224 }
225 }
226
227 // Don't suspend if KMP_BLOCKTIME is set to "infinite"
228 if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME)
229 continue;
230
231 // Don't suspend if there is a likelihood of new tasks being spawned.
232 if ((task_team != NULL) && TCR_4(task_team->tt.tt_found_tasks))
233 continue;
234
235 // If we have waited a bit more, fall asleep
236 if (TCR_4(__kmp_global.g.g_time.dt.t_value) < hibernate)
237 continue;
238
239 KF_TRACE(50, ("__kmp_wait_sleep: T#%d suspend time reached\n", th_gtid));
240
241 flag->suspend(th_gtid);
242
243 if (TCR_4(__kmp_global.g.g_done)) {
244 if (__kmp_global.g.g_abort)
245 __kmp_abort_thread();
246 break;
247 }
248 // TODO: If thread is done with work and times out, disband/free
249 }
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000250
251#if OMPT_SUPPORT && OMPT_BLAME
Jonathan Peytonb68a85d2015-09-21 18:11:22 +0000252 if (ompt_enabled &&
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000253 ompt_state != ompt_state_undefined) {
254 if (ompt_state == ompt_state_idle) {
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000255 if (ompt_callbacks.ompt_callback(ompt_event_idle_end)) {
256 ompt_callbacks.ompt_callback(ompt_event_idle_end)(th_gtid + 1);
257 }
258 } else if (ompt_callbacks.ompt_callback(ompt_event_wait_barrier_end)) {
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000259 KMP_DEBUG_ASSERT(ompt_state == ompt_state_wait_barrier ||
260 ompt_state == ompt_state_wait_barrier_implicit ||
261 ompt_state == ompt_state_wait_barrier_explicit);
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000262
263 ompt_lw_taskteam_t* team = this_thr->th.th_team->t.ompt_serialized_team_info;
264 ompt_parallel_id_t pId;
265 ompt_task_id_t tId;
266 if (team){
267 pId = team->ompt_team_info.parallel_id;
268 tId = team->ompt_task_info.task_id;
269 } else {
270 pId = this_thr->th.th_team->t.ompt_team_info.parallel_id;
271 tId = this_thr->th.th_current_task->ompt_task_info.task_id;
272 }
273 ompt_callbacks.ompt_callback(ompt_event_wait_barrier_end)(pId, tId);
274 }
275 }
276#endif
277
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000278 KMP_FSYNC_SPIN_ACQUIRED(spin);
279}
280
281/* Release any threads specified as waiting on the flag by releasing the flag and resume the waiting thread
282 if indicated by the sleep bit(s). A thread that calls __kmp_wait_template must call this function to wake
283 up the potentially sleeping thread and prevent deadlocks! */
284template <class C>
285static inline void __kmp_release_template(C *flag)
286{
287#ifdef KMP_DEBUG
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000288 int gtid = TCR_4(__kmp_init_gtid) ? __kmp_get_gtid() : -1;
289#endif
Jonathan Peytone03b62f2015-10-08 18:49:40 +0000290 KF_TRACE(20, ("__kmp_release: T#%d releasing flag(%x)\n", gtid, flag->get()));
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000291 KMP_DEBUG_ASSERT(flag->get());
292 KMP_FSYNC_RELEASING(flag->get());
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000293
294 flag->internal_release();
295
296 KF_TRACE(100, ("__kmp_release: T#%d set new spin=%d\n", gtid, flag->get(), *(flag->get())));
297
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000298 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
299 // Only need to check sleep stuff if infinite block time not set
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000300 if (flag->is_any_sleeping()) { // Are *any* of the threads that wait on this flag sleeping?
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000301 for (unsigned int i=0; i<flag->get_num_waiters(); ++i) {
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000302 kmp_info_t * waiter = flag->get_waiter(i); // if a sleeping waiter exists at i, sets current_waiter to i inside the flag
303 if (waiter) {
304 int wait_gtid = waiter->th.th_info.ds.ds_gtid;
305 // Wake up thread if needed
306 KF_TRACE(50, ("__kmp_release: T#%d waking up thread T#%d since sleep flag(%p) set\n",
307 gtid, wait_gtid, flag->get()));
308 flag->resume(wait_gtid); // unsets flag's current_waiter when done
309 }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000310 }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000311 }
312 }
313}
314
315template <typename FlagType>
316struct flag_traits {};
317
318template <>
319struct flag_traits<kmp_uint32> {
320 typedef kmp_uint32 flag_t;
321 static const flag_type t = flag32;
322 static inline flag_t tcr(flag_t f) { return TCR_4(f); }
323 static inline flag_t test_then_add4(volatile flag_t *f) { return KMP_TEST_THEN_ADD4_32((volatile kmp_int32 *)f); }
324 static inline flag_t test_then_or(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_OR32((volatile kmp_int32 *)f, v); }
325 static inline flag_t test_then_and(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_AND32((volatile kmp_int32 *)f, v); }
326};
327
328template <>
329struct flag_traits<kmp_uint64> {
330 typedef kmp_uint64 flag_t;
331 static const flag_type t = flag64;
332 static inline flag_t tcr(flag_t f) { return TCR_8(f); }
333 static inline flag_t test_then_add4(volatile flag_t *f) { return KMP_TEST_THEN_ADD4_64((volatile kmp_int64 *)f); }
334 static inline flag_t test_then_or(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_OR64((volatile kmp_int64 *)f, v); }
335 static inline flag_t test_then_and(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_AND64((volatile kmp_int64 *)f, v); }
336};
337
338template <typename FlagType>
339class kmp_basic_flag : public kmp_flag<FlagType> {
340 typedef flag_traits<FlagType> traits_type;
341 FlagType checker; /**< Value to compare flag to to check if flag has been released. */
342 kmp_info_t * waiting_threads[1]; /**< Array of threads sleeping on this thread. */
343 kmp_uint32 num_waiting_threads; /**< Number of threads sleeping on this thread. */
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000344 public:
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000345 kmp_basic_flag(volatile FlagType *p) : kmp_flag<FlagType>(p, traits_type::t), num_waiting_threads(0) {}
346 kmp_basic_flag(volatile FlagType *p, kmp_info_t *thr) : kmp_flag<FlagType>(p, traits_type::t), num_waiting_threads(1) {
347 waiting_threads[0] = thr;
348 }
349 kmp_basic_flag(volatile FlagType *p, FlagType c) : kmp_flag<FlagType>(p, traits_type::t), checker(c), num_waiting_threads(0) {}
350 /*!
351 * param i in index into waiting_threads
352 * @result the thread that is waiting at index i
353 */
354 kmp_info_t * get_waiter(kmp_uint32 i) {
355 KMP_DEBUG_ASSERT(i<num_waiting_threads);
356 return waiting_threads[i];
357 }
358 /*!
359 * @result num_waiting_threads
360 */
361 kmp_uint32 get_num_waiters() { return num_waiting_threads; }
362 /*!
363 * @param thr in the thread which is now waiting
364 *
365 * Insert a waiting thread at index 0.
366 */
367 void set_waiter(kmp_info_t *thr) {
368 waiting_threads[0] = thr;
369 num_waiting_threads = 1;
370 }
371 /*!
372 * @result true if the flag object has been released.
373 */
374 bool done_check() { return traits_type::tcr(*(this->get())) == checker; }
375 /*!
376 * @param old_loc in old value of flag
377 * @result true if the flag's old value indicates it was released.
378 */
379 bool done_check_val(FlagType old_loc) { return old_loc == checker; }
380 /*!
381 * @result true if the flag object is not yet released.
382 * Used in __kmp_wait_template like:
383 * @code
384 * while (flag.notdone_check()) { pause(); }
385 * @endcode
386 */
387 bool notdone_check() { return traits_type::tcr(*(this->get())) != checker; }
388 /*!
389 * @result Actual flag value before release was applied.
390 * Trigger all waiting threads to run by modifying flag to release state.
391 */
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000392 void internal_release() {
393 (void) traits_type::test_then_add4((volatile FlagType *)this->get());
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000394 }
395 /*!
396 * @result Actual flag value before sleep bit(s) set.
397 * Notes that there is at least one thread sleeping on the flag by setting sleep bit(s).
398 */
399 FlagType set_sleeping() {
400 return traits_type::test_then_or((volatile FlagType *)this->get(), KMP_BARRIER_SLEEP_STATE);
401 }
402 /*!
403 * @result Actual flag value before sleep bit(s) cleared.
404 * Notes that there are no longer threads sleeping on the flag by clearing sleep bit(s).
405 */
406 FlagType unset_sleeping() {
407 return traits_type::test_then_and((volatile FlagType *)this->get(), ~KMP_BARRIER_SLEEP_STATE);
408 }
409 /*!
410 * @param old_loc in old value of flag
411 * Test whether there are threads sleeping on the flag's old value in old_loc.
412 */
413 bool is_sleeping_val(FlagType old_loc) { return old_loc & KMP_BARRIER_SLEEP_STATE; }
414 /*!
415 * Test whether there are threads sleeping on the flag.
416 */
417 bool is_sleeping() { return is_sleeping_val(*(this->get())); }
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000418 bool is_any_sleeping() { return is_sleeping_val(*(this->get())); }
419 kmp_uint8 *get_stolen() { return NULL; }
420 enum barrier_type get_bt() { return bs_last_barrier; }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000421};
422
423class kmp_flag_32 : public kmp_basic_flag<kmp_uint32> {
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000424 public:
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000425 kmp_flag_32(volatile kmp_uint32 *p) : kmp_basic_flag<kmp_uint32>(p) {}
426 kmp_flag_32(volatile kmp_uint32 *p, kmp_info_t *thr) : kmp_basic_flag<kmp_uint32>(p, thr) {}
427 kmp_flag_32(volatile kmp_uint32 *p, kmp_uint32 c) : kmp_basic_flag<kmp_uint32>(p, c) {}
428 void suspend(int th_gtid) { __kmp_suspend_32(th_gtid, this); }
429 void resume(int th_gtid) { __kmp_resume_32(th_gtid, this); }
430 int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin, int *thread_finished
431 USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained) {
432 return __kmp_execute_tasks_32(this_thr, gtid, this, final_spin, thread_finished
433 USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
434 }
435 void wait(kmp_info_t *this_thr, int final_spin
436 USE_ITT_BUILD_ARG(void * itt_sync_obj)) {
437 __kmp_wait_template(this_thr, this, final_spin
438 USE_ITT_BUILD_ARG(itt_sync_obj));
439 }
440 void release() { __kmp_release_template(this); }
Jonathan Peyton3f5dfc22015-11-09 16:31:51 +0000441 flag_type get_ptr_type() { return flag32; }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000442};
443
444class kmp_flag_64 : public kmp_basic_flag<kmp_uint64> {
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000445 public:
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000446 kmp_flag_64(volatile kmp_uint64 *p) : kmp_basic_flag<kmp_uint64>(p) {}
447 kmp_flag_64(volatile kmp_uint64 *p, kmp_info_t *thr) : kmp_basic_flag<kmp_uint64>(p, thr) {}
448 kmp_flag_64(volatile kmp_uint64 *p, kmp_uint64 c) : kmp_basic_flag<kmp_uint64>(p, c) {}
449 void suspend(int th_gtid) { __kmp_suspend_64(th_gtid, this); }
450 void resume(int th_gtid) { __kmp_resume_64(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_64(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 flag64; }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000463};
464
465// Hierarchical 64-bit on-core barrier instantiation
466class kmp_flag_oncore : public kmp_flag<kmp_uint64> {
467 kmp_uint64 checker;
468 kmp_info_t * waiting_threads[1];
469 kmp_uint32 num_waiting_threads;
470 kmp_uint32 offset; /**< Portion of flag that is of interest for an operation. */
471 bool flag_switch; /**< Indicates a switch in flag location. */
472 enum barrier_type bt; /**< Barrier type. */
473 kmp_info_t * this_thr; /**< Thread that may be redirected to different flag location. */
474#if USE_ITT_BUILD
475 void *itt_sync_obj; /**< ITT object that must be passed to new flag location. */
476#endif
Jonathan Peyton1e7a1dd2015-06-04 17:29:13 +0000477 unsigned char& byteref(volatile kmp_uint64* loc, size_t offset) { return ((unsigned char *)loc)[offset]; }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000478public:
479 kmp_flag_oncore(volatile kmp_uint64 *p)
480 : kmp_flag<kmp_uint64>(p, flag_oncore), num_waiting_threads(0), flag_switch(false) {}
481 kmp_flag_oncore(volatile kmp_uint64 *p, kmp_uint32 idx)
Jonathan Peytonc98d0302015-06-03 17:26:47 +0000482 : kmp_flag<kmp_uint64>(p, flag_oncore), num_waiting_threads(0), offset(idx), flag_switch(false) {}
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000483 kmp_flag_oncore(volatile kmp_uint64 *p, kmp_uint64 c, kmp_uint32 idx, enum barrier_type bar_t,
484 kmp_info_t * thr
485#if USE_ITT_BUILD
486 , void *itt
487#endif
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000488 )
Jonathan Peytonc98d0302015-06-03 17:26:47 +0000489 : kmp_flag<kmp_uint64>(p, flag_oncore), checker(c), num_waiting_threads(0), offset(idx),
490 flag_switch(false), bt(bar_t), this_thr(thr)
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000491#if USE_ITT_BUILD
492 , itt_sync_obj(itt)
493#endif
Jonathan Peytonc98d0302015-06-03 17:26:47 +0000494 {}
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000495 kmp_info_t * get_waiter(kmp_uint32 i) {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000496 KMP_DEBUG_ASSERT(i<num_waiting_threads);
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000497 return waiting_threads[i];
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000498 }
499 kmp_uint32 get_num_waiters() { return num_waiting_threads; }
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000500 void set_waiter(kmp_info_t *thr) {
501 waiting_threads[0] = thr;
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000502 num_waiting_threads = 1;
503 }
504 bool done_check_val(kmp_uint64 old_loc) { return byteref(&old_loc,offset) == checker; }
505 bool done_check() { return done_check_val(*get()); }
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000506 bool notdone_check() {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000507 // Calculate flag_switch
508 if (this_thr->th.th_bar[bt].bb.wait_flag == KMP_BARRIER_SWITCH_TO_OWN_FLAG)
509 flag_switch = true;
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000510 if (byteref(get(),offset) != 1 && !flag_switch)
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000511 return true;
512 else if (flag_switch) {
513 this_thr->th.th_bar[bt].bb.wait_flag = KMP_BARRIER_SWITCHING;
514 kmp_flag_64 flag(&this_thr->th.th_bar[bt].bb.b_go, (kmp_uint64)KMP_BARRIER_STATE_BUMP);
515 __kmp_wait_64(this_thr, &flag, TRUE
516#if USE_ITT_BUILD
517 , itt_sync_obj
518#endif
519 );
520 }
521 return false;
522 }
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000523 void internal_release() {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000524 if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME) {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000525 byteref(get(),offset) = 1;
526 }
527 else {
528 kmp_uint64 mask=0;
529 byteref(&mask,offset) = 1;
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000530 (void) KMP_TEST_THEN_OR64((volatile kmp_int64 *)get(), mask);
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000531 }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000532 }
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000533 kmp_uint64 set_sleeping() {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000534 return KMP_TEST_THEN_OR64((kmp_int64 volatile *)get(), KMP_BARRIER_SLEEP_STATE);
535 }
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000536 kmp_uint64 unset_sleeping() {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000537 return KMP_TEST_THEN_AND64((kmp_int64 volatile *)get(), ~KMP_BARRIER_SLEEP_STATE);
538 }
539 bool is_sleeping_val(kmp_uint64 old_loc) { return old_loc & KMP_BARRIER_SLEEP_STATE; }
540 bool is_sleeping() { return is_sleeping_val(*get()); }
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000541 bool is_any_sleeping() { return is_sleeping_val(*get()); }
542 void wait(kmp_info_t *this_thr, int final_spin) {
543 __kmp_wait_template<kmp_flag_oncore>(this_thr, this, final_spin
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000544 USE_ITT_BUILD_ARG(itt_sync_obj));
545 }
546 void release() { __kmp_release_template(this); }
547 void suspend(int th_gtid) { __kmp_suspend_oncore(th_gtid, this); }
548 void resume(int th_gtid) { __kmp_resume_oncore(th_gtid, this); }
549 int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin, int *thread_finished
550 USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained) {
551 return __kmp_execute_tasks_oncore(this_thr, gtid, this, final_spin, thread_finished
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000552 USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000553 }
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000554 kmp_uint8 *get_stolen() { return NULL; }
555 enum barrier_type get_bt() { return bt; }
Jonathan Peyton3f5dfc22015-11-09 16:31:51 +0000556 flag_type get_ptr_type() { return flag_oncore; }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000557};
558
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000559
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000560/*!
561@}
562*/
563
564#endif // KMP_WAIT_RELEASE_H