blob: bed40170e03440ac91b4d0ae353b0688254f4da0 [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>
Jonathan Peyton1a78c632016-01-11 20:28:55 +000089static inline void
90__kmp_wait_template(kmp_info_t *this_thr, C *flag, int final_spin
91 USE_ITT_BUILD_ARG(void * itt_sync_obj) )
Jim Cownie4cc4bb42014-10-07 16:25:50 +000092{
93 // NOTE: We may not belong to a team at this point.
94 volatile typename C::flag_t *spin = flag->get();
95 kmp_uint32 spins;
96 kmp_uint32 hibernate;
97 int th_gtid;
98 int tasks_completed = FALSE;
99
100 KMP_FSYNC_SPIN_INIT(spin, NULL);
101 if (flag->done_check()) {
102 KMP_FSYNC_SPIN_ACQUIRED(spin);
103 return;
104 }
105 th_gtid = this_thr->th.th_info.ds.ds_gtid;
106 KA_TRACE(20, ("__kmp_wait_sleep: T#%d waiting for flag(%p)\n", th_gtid, flag));
107
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000108#if OMPT_SUPPORT && OMPT_BLAME
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000109 ompt_state_t ompt_state = this_thr->th.ompt_thread_info.state;
Jonathan Peytonb68a85d2015-09-21 18:11:22 +0000110 if (ompt_enabled &&
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000111 ompt_state != ompt_state_undefined) {
112 if (ompt_state == ompt_state_idle) {
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000113 if (ompt_callbacks.ompt_callback(ompt_event_idle_begin)) {
114 ompt_callbacks.ompt_callback(ompt_event_idle_begin)(th_gtid + 1);
115 }
116 } else if (ompt_callbacks.ompt_callback(ompt_event_wait_barrier_begin)) {
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000117 KMP_DEBUG_ASSERT(ompt_state == ompt_state_wait_barrier ||
118 ompt_state == ompt_state_wait_barrier_implicit ||
119 ompt_state == ompt_state_wait_barrier_explicit);
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000120
121 ompt_lw_taskteam_t* team = this_thr->th.th_team->t.ompt_serialized_team_info;
122 ompt_parallel_id_t pId;
123 ompt_task_id_t tId;
124 if (team){
125 pId = team->ompt_team_info.parallel_id;
126 tId = team->ompt_task_info.task_id;
127 } else {
128 pId = this_thr->th.th_team->t.ompt_team_info.parallel_id;
129 tId = this_thr->th.th_current_task->ompt_task_info.task_id;
130 }
131 ompt_callbacks.ompt_callback(ompt_event_wait_barrier_begin)(pId, tId);
132 }
133 }
134#endif
135
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000136 // Setup for waiting
137 KMP_INIT_YIELD(spins);
138
139 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
140 // The worker threads cannot rely on the team struct existing at this point.
141 // Use the bt values cached in the thread struct instead.
142#ifdef KMP_ADJUST_BLOCKTIME
143 if (__kmp_zero_bt && !this_thr->th.th_team_bt_set)
144 // Force immediate suspend if not set by user and more threads than available procs
145 hibernate = 0;
146 else
147 hibernate = this_thr->th.th_team_bt_intervals;
148#else
149 hibernate = this_thr->th.th_team_bt_intervals;
150#endif /* KMP_ADJUST_BLOCKTIME */
151
152 /* If the blocktime is nonzero, we want to make sure that we spin wait for the entirety
153 of the specified #intervals, plus up to one interval more. This increment make
154 certain that this thread doesn't go to sleep too soon. */
155 if (hibernate != 0)
156 hibernate++;
157
158 // Add in the current time value.
159 hibernate += TCR_4(__kmp_global.g.g_time.dt.t_value);
160 KF_TRACE(20, ("__kmp_wait_sleep: T#%d now=%d, hibernate=%d, intervals=%d\n",
161 th_gtid, __kmp_global.g.g_time.dt.t_value, hibernate,
162 hibernate - __kmp_global.g.g_time.dt.t_value));
163 }
Jonathan Peyton1bd61b42015-10-08 19:44:16 +0000164
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000165 KMP_MB();
166
167 // Main wait spin loop
168 while (flag->notdone_check()) {
169 int in_pool;
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000170 kmp_task_team_t * task_team = NULL;
171 if (__kmp_tasking_mode != tskm_immediate_exec) {
172 task_team = this_thr->th.th_task_team;
Jonathan Peyton4cfe93c2016-03-29 21:08:29 +0000173 /* If the thread's task team pointer is NULL, it means one of 3 things:
174 1) A newly-created thread is first being released by __kmp_fork_barrier(), and
175 its task team has not been set up yet.
176 2) All tasks have been executed to completion.
177 3) Tasking is off for this region. This could be because we are in a serialized region
178 (perhaps the outer one), or else tasking was manually disabled (KMP_TASKING=0). */
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000179 if (task_team != NULL) {
Jonathan Peyton54127982015-11-04 21:37:48 +0000180 if (TCR_SYNC_4(task_team->tt.tt_active)) {
181 if (KMP_TASKING_ENABLED(task_team))
182 flag->execute_tasks(this_thr, th_gtid, final_spin, &tasks_completed
183 USE_ITT_BUILD_ARG(itt_sync_obj), 0);
184 }
185 else {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000186 KMP_DEBUG_ASSERT(!KMP_MASTER_TID(this_thr->th.th_info.ds.ds_tid));
Jonathan Peyton54127982015-11-04 21:37:48 +0000187 this_thr->th.th_task_team = NULL;
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000188 }
189 } // if
190 } // if
191
192 KMP_FSYNC_SPIN_PREPARE(spin);
193 if (TCR_4(__kmp_global.g.g_done)) {
194 if (__kmp_global.g.g_abort)
195 __kmp_abort_thread();
196 break;
197 }
198
199 // If we are oversubscribed, or have waited a bit (and KMP_LIBRARY=throughput), then yield
200 KMP_YIELD(TCR_4(__kmp_nth) > __kmp_avail_proc);
201 // TODO: Should it be number of cores instead of thread contexts? Like:
202 // KMP_YIELD(TCR_4(__kmp_nth) > __kmp_ncores);
203 // Need performance improvement data to make the change...
204 KMP_YIELD_SPIN(spins);
205
206 // Check if this thread was transferred from a team
207 // to the thread pool (or vice-versa) while spinning.
208 in_pool = !!TCR_4(this_thr->th.th_in_pool);
209 if (in_pool != !!this_thr->th.th_active_in_pool) {
210 if (in_pool) { // Recently transferred from team to pool
211 KMP_TEST_THEN_INC32((kmp_int32 *)&__kmp_thread_pool_active_nth);
212 this_thr->th.th_active_in_pool = TRUE;
213 /* Here, we cannot assert that:
214 KMP_DEBUG_ASSERT(TCR_4(__kmp_thread_pool_active_nth) <= __kmp_thread_pool_nth);
215 __kmp_thread_pool_nth is inc/dec'd by the master thread while the fork/join
216 lock is held, whereas __kmp_thread_pool_active_nth is inc/dec'd asynchronously
217 by the workers. The two can get out of sync for brief periods of time. */
218 }
219 else { // Recently transferred from pool to team
220 KMP_TEST_THEN_DEC32((kmp_int32 *) &__kmp_thread_pool_active_nth);
221 KMP_DEBUG_ASSERT(TCR_4(__kmp_thread_pool_active_nth) >= 0);
222 this_thr->th.th_active_in_pool = FALSE;
223 }
224 }
225
226 // Don't suspend if KMP_BLOCKTIME is set to "infinite"
227 if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME)
228 continue;
229
230 // Don't suspend if there is a likelihood of new tasks being spawned.
231 if ((task_team != NULL) && TCR_4(task_team->tt.tt_found_tasks))
232 continue;
233
234 // If we have waited a bit more, fall asleep
235 if (TCR_4(__kmp_global.g.g_time.dt.t_value) < hibernate)
236 continue;
237
238 KF_TRACE(50, ("__kmp_wait_sleep: T#%d suspend time reached\n", th_gtid));
239
240 flag->suspend(th_gtid);
241
242 if (TCR_4(__kmp_global.g.g_done)) {
243 if (__kmp_global.g.g_abort)
244 __kmp_abort_thread();
245 break;
246 }
247 // TODO: If thread is done with work and times out, disband/free
248 }
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000249
250#if OMPT_SUPPORT && OMPT_BLAME
Jonathan Peytonb68a85d2015-09-21 18:11:22 +0000251 if (ompt_enabled &&
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000252 ompt_state != ompt_state_undefined) {
253 if (ompt_state == ompt_state_idle) {
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000254 if (ompt_callbacks.ompt_callback(ompt_event_idle_end)) {
255 ompt_callbacks.ompt_callback(ompt_event_idle_end)(th_gtid + 1);
256 }
257 } else if (ompt_callbacks.ompt_callback(ompt_event_wait_barrier_end)) {
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000258 KMP_DEBUG_ASSERT(ompt_state == ompt_state_wait_barrier ||
259 ompt_state == ompt_state_wait_barrier_implicit ||
260 ompt_state == ompt_state_wait_barrier_explicit);
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000261
262 ompt_lw_taskteam_t* team = this_thr->th.th_team->t.ompt_serialized_team_info;
263 ompt_parallel_id_t pId;
264 ompt_task_id_t tId;
265 if (team){
266 pId = team->ompt_team_info.parallel_id;
267 tId = team->ompt_task_info.task_id;
268 } else {
269 pId = this_thr->th.th_team->t.ompt_team_info.parallel_id;
270 tId = this_thr->th.th_current_task->ompt_task_info.task_id;
271 }
272 ompt_callbacks.ompt_callback(ompt_event_wait_barrier_end)(pId, tId);
273 }
274 }
275#endif
276
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000277 KMP_FSYNC_SPIN_ACQUIRED(spin);
278}
279
280/* Release any threads specified as waiting on the flag by releasing the flag and resume the waiting thread
281 if indicated by the sleep bit(s). A thread that calls __kmp_wait_template must call this function to wake
282 up the potentially sleeping thread and prevent deadlocks! */
283template <class C>
Jonathan Peyton1a78c632016-01-11 20:28:55 +0000284static inline void
285__kmp_release_template(C *flag)
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000286{
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 Peyton6cb33c62015-12-18 23:15:35 +0000293
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000294 flag->internal_release();
Jonathan Peyton6cb33c62015-12-18 23:15:35 +0000295
Jonathan Peytona0e159f2015-10-08 18:23:38 +0000296 KF_TRACE(100, ("__kmp_release: T#%d set new spin=%d\n", gtid, flag->get(), *(flag->get())));
Jonathan Peyton6cb33c62015-12-18 23:15:35 +0000297
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