blob: 261df2762f643c7075c782a82810b20a149191d5 [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 /*!
59 * @result the flag_type
60 */
61 flag_type get_type() { return t; }
62 // Derived classes must provide the following:
63 /*
64 kmp_info_t * get_waiter(kmp_uint32 i);
65 kmp_uint32 get_num_waiters();
66 bool done_check();
67 bool done_check_val(P old_loc);
68 bool notdone_check();
69 P internal_release();
70 P set_sleeping();
71 P unset_sleeping();
72 bool is_sleeping();
73 bool is_sleeping_val(P old_loc);
74 */
75};
76
77/* Spin wait loop that first does pause, then yield, then sleep. A thread that calls __kmp_wait_*
78 must make certain that another thread calls __kmp_release to wake it back up to prevent deadlocks! */
79template <class C>
80static inline void __kmp_wait_template(kmp_info_t *this_thr, C *flag, int final_spin
81 USE_ITT_BUILD_ARG(void * itt_sync_obj) )
82{
83 // NOTE: We may not belong to a team at this point.
84 volatile typename C::flag_t *spin = flag->get();
85 kmp_uint32 spins;
86 kmp_uint32 hibernate;
87 int th_gtid;
88 int tasks_completed = FALSE;
89
90 KMP_FSYNC_SPIN_INIT(spin, NULL);
91 if (flag->done_check()) {
92 KMP_FSYNC_SPIN_ACQUIRED(spin);
93 return;
94 }
95 th_gtid = this_thr->th.th_info.ds.ds_gtid;
96 KA_TRACE(20, ("__kmp_wait_sleep: T#%d waiting for flag(%p)\n", th_gtid, flag));
97
Andrey Churbanovd7d088f2015-04-29 16:42:24 +000098#if OMPT_SUPPORT && OMPT_BLAME
Jonathan Peyton6d247f72015-09-10 21:33:50 +000099 ompt_state_t ompt_state = this_thr->th.ompt_thread_info.state;
Jonathan Peytonb68a85d2015-09-21 18:11:22 +0000100 if (ompt_enabled &&
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000101 ompt_state != ompt_state_undefined) {
102 if (ompt_state == ompt_state_idle) {
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000103 if (ompt_callbacks.ompt_callback(ompt_event_idle_begin)) {
104 ompt_callbacks.ompt_callback(ompt_event_idle_begin)(th_gtid + 1);
105 }
106 } else if (ompt_callbacks.ompt_callback(ompt_event_wait_barrier_begin)) {
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000107 KMP_DEBUG_ASSERT(ompt_state == ompt_state_wait_barrier ||
108 ompt_state == ompt_state_wait_barrier_implicit ||
109 ompt_state == ompt_state_wait_barrier_explicit);
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000110
111 ompt_lw_taskteam_t* team = this_thr->th.th_team->t.ompt_serialized_team_info;
112 ompt_parallel_id_t pId;
113 ompt_task_id_t tId;
114 if (team){
115 pId = team->ompt_team_info.parallel_id;
116 tId = team->ompt_task_info.task_id;
117 } else {
118 pId = this_thr->th.th_team->t.ompt_team_info.parallel_id;
119 tId = this_thr->th.th_current_task->ompt_task_info.task_id;
120 }
121 ompt_callbacks.ompt_callback(ompt_event_wait_barrier_begin)(pId, tId);
122 }
123 }
124#endif
125
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000126 // Setup for waiting
127 KMP_INIT_YIELD(spins);
128
129 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
130 // The worker threads cannot rely on the team struct existing at this point.
131 // Use the bt values cached in the thread struct instead.
132#ifdef KMP_ADJUST_BLOCKTIME
133 if (__kmp_zero_bt && !this_thr->th.th_team_bt_set)
134 // Force immediate suspend if not set by user and more threads than available procs
135 hibernate = 0;
136 else
137 hibernate = this_thr->th.th_team_bt_intervals;
138#else
139 hibernate = this_thr->th.th_team_bt_intervals;
140#endif /* KMP_ADJUST_BLOCKTIME */
141
142 /* If the blocktime is nonzero, we want to make sure that we spin wait for the entirety
143 of the specified #intervals, plus up to one interval more. This increment make
144 certain that this thread doesn't go to sleep too soon. */
145 if (hibernate != 0)
146 hibernate++;
147
148 // Add in the current time value.
149 hibernate += TCR_4(__kmp_global.g.g_time.dt.t_value);
150 KF_TRACE(20, ("__kmp_wait_sleep: T#%d now=%d, hibernate=%d, intervals=%d\n",
151 th_gtid, __kmp_global.g.g_time.dt.t_value, hibernate,
152 hibernate - __kmp_global.g.g_time.dt.t_value));
153 }
154 KMP_MB();
155
156 // Main wait spin loop
157 while (flag->notdone_check()) {
158 int in_pool;
159
160 /* If the task team is NULL, it means one of things:
161 1) A newly-created thread is first being released by __kmp_fork_barrier(), and
162 its task team has not been set up yet.
163 2) All tasks have been executed to completion, this thread has decremented the task
164 team's ref ct and possibly deallocated it, and should no longer reference it.
165 3) Tasking is off for this region. This could be because we are in a serialized region
166 (perhaps the outer one), or else tasking was manually disabled (KMP_TASKING=0). */
167 kmp_task_team_t * task_team = NULL;
168 if (__kmp_tasking_mode != tskm_immediate_exec) {
169 task_team = this_thr->th.th_task_team;
170 if (task_team != NULL) {
171 if (!TCR_SYNC_4(task_team->tt.tt_active)) {
172 KMP_DEBUG_ASSERT(!KMP_MASTER_TID(this_thr->th.th_info.ds.ds_tid));
173 __kmp_unref_task_team(task_team, this_thr);
Andrey Churbanov6d224db2015-02-10 18:37:43 +0000174 } else if (KMP_TASKING_ENABLED(task_team)) {
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000175 flag->execute_tasks(this_thr, th_gtid, final_spin, &tasks_completed
176 USE_ITT_BUILD_ARG(itt_sync_obj), 0);
177 }
178 } // if
179 } // if
180
181 KMP_FSYNC_SPIN_PREPARE(spin);
182 if (TCR_4(__kmp_global.g.g_done)) {
183 if (__kmp_global.g.g_abort)
184 __kmp_abort_thread();
185 break;
186 }
187
188 // If we are oversubscribed, or have waited a bit (and KMP_LIBRARY=throughput), then yield
189 KMP_YIELD(TCR_4(__kmp_nth) > __kmp_avail_proc);
190 // TODO: Should it be number of cores instead of thread contexts? Like:
191 // KMP_YIELD(TCR_4(__kmp_nth) > __kmp_ncores);
192 // Need performance improvement data to make the change...
193 KMP_YIELD_SPIN(spins);
194
195 // Check if this thread was transferred from a team
196 // to the thread pool (or vice-versa) while spinning.
197 in_pool = !!TCR_4(this_thr->th.th_in_pool);
198 if (in_pool != !!this_thr->th.th_active_in_pool) {
199 if (in_pool) { // Recently transferred from team to pool
200 KMP_TEST_THEN_INC32((kmp_int32 *)&__kmp_thread_pool_active_nth);
201 this_thr->th.th_active_in_pool = TRUE;
202 /* Here, we cannot assert that:
203 KMP_DEBUG_ASSERT(TCR_4(__kmp_thread_pool_active_nth) <= __kmp_thread_pool_nth);
204 __kmp_thread_pool_nth is inc/dec'd by the master thread while the fork/join
205 lock is held, whereas __kmp_thread_pool_active_nth is inc/dec'd asynchronously
206 by the workers. The two can get out of sync for brief periods of time. */
207 }
208 else { // Recently transferred from pool to team
209 KMP_TEST_THEN_DEC32((kmp_int32 *) &__kmp_thread_pool_active_nth);
210 KMP_DEBUG_ASSERT(TCR_4(__kmp_thread_pool_active_nth) >= 0);
211 this_thr->th.th_active_in_pool = FALSE;
212 }
213 }
214
215 // Don't suspend if KMP_BLOCKTIME is set to "infinite"
216 if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME)
217 continue;
218
219 // Don't suspend if there is a likelihood of new tasks being spawned.
220 if ((task_team != NULL) && TCR_4(task_team->tt.tt_found_tasks))
221 continue;
222
223 // If we have waited a bit more, fall asleep
224 if (TCR_4(__kmp_global.g.g_time.dt.t_value) < hibernate)
225 continue;
226
227 KF_TRACE(50, ("__kmp_wait_sleep: T#%d suspend time reached\n", th_gtid));
228
229 flag->suspend(th_gtid);
230
231 if (TCR_4(__kmp_global.g.g_done)) {
232 if (__kmp_global.g.g_abort)
233 __kmp_abort_thread();
234 break;
235 }
236 // TODO: If thread is done with work and times out, disband/free
237 }
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000238
239#if OMPT_SUPPORT && OMPT_BLAME
Jonathan Peytonb68a85d2015-09-21 18:11:22 +0000240 if (ompt_enabled &&
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000241 ompt_state != ompt_state_undefined) {
242 if (ompt_state == ompt_state_idle) {
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000243 if (ompt_callbacks.ompt_callback(ompt_event_idle_end)) {
244 ompt_callbacks.ompt_callback(ompt_event_idle_end)(th_gtid + 1);
245 }
246 } else if (ompt_callbacks.ompt_callback(ompt_event_wait_barrier_end)) {
Jonathan Peyton6d247f72015-09-10 21:33:50 +0000247 KMP_DEBUG_ASSERT(ompt_state == ompt_state_wait_barrier ||
248 ompt_state == ompt_state_wait_barrier_implicit ||
249 ompt_state == ompt_state_wait_barrier_explicit);
Andrey Churbanovd7d088f2015-04-29 16:42:24 +0000250
251 ompt_lw_taskteam_t* team = this_thr->th.th_team->t.ompt_serialized_team_info;
252 ompt_parallel_id_t pId;
253 ompt_task_id_t tId;
254 if (team){
255 pId = team->ompt_team_info.parallel_id;
256 tId = team->ompt_task_info.task_id;
257 } else {
258 pId = this_thr->th.th_team->t.ompt_team_info.parallel_id;
259 tId = this_thr->th.th_current_task->ompt_task_info.task_id;
260 }
261 ompt_callbacks.ompt_callback(ompt_event_wait_barrier_end)(pId, tId);
262 }
263 }
264#endif
265
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000266 KMP_FSYNC_SPIN_ACQUIRED(spin);
267}
268
269/* Release any threads specified as waiting on the flag by releasing the flag and resume the waiting thread
270 if indicated by the sleep bit(s). A thread that calls __kmp_wait_template must call this function to wake
271 up the potentially sleeping thread and prevent deadlocks! */
272template <class C>
273static inline void __kmp_release_template(C *flag)
274{
275#ifdef KMP_DEBUG
276 // FIX ME
277 kmp_info_t * wait_thr = flag->get_waiter(0);
278 int target_gtid = wait_thr->th.th_info.ds.ds_gtid;
279 int gtid = TCR_4(__kmp_init_gtid) ? __kmp_get_gtid() : -1;
280#endif
281 KF_TRACE(20, ("__kmp_release: T#%d releasing T#%d spin(%p)\n", gtid, target_gtid, flag->get()));
282 KMP_DEBUG_ASSERT(flag->get());
283 KMP_FSYNC_RELEASING(flag->get());
284
285 typename C::flag_t old_spin = flag->internal_release();
286
287 KF_TRACE(100, ("__kmp_release: T#%d old spin(%p)=%d, set new spin=%d\n",
288 gtid, flag->get(), old_spin, *(flag->get())));
289
290 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
291 // Only need to check sleep stuff if infinite block time not set
292 if (flag->is_sleeping_val(old_spin)) {
293 for (unsigned int i=0; i<flag->get_num_waiters(); ++i) {
294 kmp_info_t * waiter = flag->get_waiter(i);
295 int wait_gtid = waiter->th.th_info.ds.ds_gtid;
296 // Wake up thread if needed
297 KF_TRACE(50, ("__kmp_release: T#%d waking up thread T#%d since sleep spin(%p) set\n",
298 gtid, wait_gtid, flag->get()));
299 flag->resume(wait_gtid);
300 }
301 } else {
302 KF_TRACE(50, ("__kmp_release: T#%d don't wake up thread T#%d since sleep spin(%p) not set\n",
303 gtid, target_gtid, flag->get()));
304 }
305 }
306}
307
308template <typename FlagType>
309struct flag_traits {};
310
311template <>
312struct flag_traits<kmp_uint32> {
313 typedef kmp_uint32 flag_t;
314 static const flag_type t = flag32;
315 static inline flag_t tcr(flag_t f) { return TCR_4(f); }
316 static inline flag_t test_then_add4(volatile flag_t *f) { return KMP_TEST_THEN_ADD4_32((volatile kmp_int32 *)f); }
317 static inline flag_t test_then_or(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_OR32((volatile kmp_int32 *)f, v); }
318 static inline flag_t test_then_and(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_AND32((volatile kmp_int32 *)f, v); }
319};
320
321template <>
322struct flag_traits<kmp_uint64> {
323 typedef kmp_uint64 flag_t;
324 static const flag_type t = flag64;
325 static inline flag_t tcr(flag_t f) { return TCR_8(f); }
326 static inline flag_t test_then_add4(volatile flag_t *f) { return KMP_TEST_THEN_ADD4_64((volatile kmp_int64 *)f); }
327 static inline flag_t test_then_or(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_OR64((volatile kmp_int64 *)f, v); }
328 static inline flag_t test_then_and(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_AND64((volatile kmp_int64 *)f, v); }
329};
330
331template <typename FlagType>
332class kmp_basic_flag : public kmp_flag<FlagType> {
333 typedef flag_traits<FlagType> traits_type;
334 FlagType checker; /**< Value to compare flag to to check if flag has been released. */
335 kmp_info_t * waiting_threads[1]; /**< Array of threads sleeping on this thread. */
336 kmp_uint32 num_waiting_threads; /**< Number of threads sleeping on this thread. */
337public:
338 kmp_basic_flag(volatile FlagType *p) : kmp_flag<FlagType>(p, traits_type::t), num_waiting_threads(0) {}
339 kmp_basic_flag(volatile FlagType *p, kmp_info_t *thr) : kmp_flag<FlagType>(p, traits_type::t), num_waiting_threads(1) {
340 waiting_threads[0] = thr;
341 }
342 kmp_basic_flag(volatile FlagType *p, FlagType c) : kmp_flag<FlagType>(p, traits_type::t), checker(c), num_waiting_threads(0) {}
343 /*!
344 * param i in index into waiting_threads
345 * @result the thread that is waiting at index i
346 */
347 kmp_info_t * get_waiter(kmp_uint32 i) {
348 KMP_DEBUG_ASSERT(i<num_waiting_threads);
349 return waiting_threads[i];
350 }
351 /*!
352 * @result num_waiting_threads
353 */
354 kmp_uint32 get_num_waiters() { return num_waiting_threads; }
355 /*!
356 * @param thr in the thread which is now waiting
357 *
358 * Insert a waiting thread at index 0.
359 */
360 void set_waiter(kmp_info_t *thr) {
361 waiting_threads[0] = thr;
362 num_waiting_threads = 1;
363 }
364 /*!
365 * @result true if the flag object has been released.
366 */
367 bool done_check() { return traits_type::tcr(*(this->get())) == checker; }
368 /*!
369 * @param old_loc in old value of flag
370 * @result true if the flag's old value indicates it was released.
371 */
372 bool done_check_val(FlagType old_loc) { return old_loc == checker; }
373 /*!
374 * @result true if the flag object is not yet released.
375 * Used in __kmp_wait_template like:
376 * @code
377 * while (flag.notdone_check()) { pause(); }
378 * @endcode
379 */
380 bool notdone_check() { return traits_type::tcr(*(this->get())) != checker; }
381 /*!
382 * @result Actual flag value before release was applied.
383 * Trigger all waiting threads to run by modifying flag to release state.
384 */
385 FlagType internal_release() {
386 return traits_type::test_then_add4((volatile FlagType *)this->get());
387 }
388 /*!
389 * @result Actual flag value before sleep bit(s) set.
390 * Notes that there is at least one thread sleeping on the flag by setting sleep bit(s).
391 */
392 FlagType set_sleeping() {
393 return traits_type::test_then_or((volatile FlagType *)this->get(), KMP_BARRIER_SLEEP_STATE);
394 }
395 /*!
396 * @result Actual flag value before sleep bit(s) cleared.
397 * Notes that there are no longer threads sleeping on the flag by clearing sleep bit(s).
398 */
399 FlagType unset_sleeping() {
400 return traits_type::test_then_and((volatile FlagType *)this->get(), ~KMP_BARRIER_SLEEP_STATE);
401 }
402 /*!
403 * @param old_loc in old value of flag
404 * Test whether there are threads sleeping on the flag's old value in old_loc.
405 */
406 bool is_sleeping_val(FlagType old_loc) { return old_loc & KMP_BARRIER_SLEEP_STATE; }
407 /*!
408 * Test whether there are threads sleeping on the flag.
409 */
410 bool is_sleeping() { return is_sleeping_val(*(this->get())); }
411};
412
413class kmp_flag_32 : public kmp_basic_flag<kmp_uint32> {
414public:
415 kmp_flag_32(volatile kmp_uint32 *p) : kmp_basic_flag<kmp_uint32>(p) {}
416 kmp_flag_32(volatile kmp_uint32 *p, kmp_info_t *thr) : kmp_basic_flag<kmp_uint32>(p, thr) {}
417 kmp_flag_32(volatile kmp_uint32 *p, kmp_uint32 c) : kmp_basic_flag<kmp_uint32>(p, c) {}
418 void suspend(int th_gtid) { __kmp_suspend_32(th_gtid, this); }
419 void resume(int th_gtid) { __kmp_resume_32(th_gtid, this); }
420 int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin, int *thread_finished
421 USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained) {
422 return __kmp_execute_tasks_32(this_thr, gtid, this, final_spin, thread_finished
423 USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
424 }
425 void wait(kmp_info_t *this_thr, int final_spin
426 USE_ITT_BUILD_ARG(void * itt_sync_obj)) {
427 __kmp_wait_template(this_thr, this, final_spin
428 USE_ITT_BUILD_ARG(itt_sync_obj));
429 }
430 void release() { __kmp_release_template(this); }
431};
432
433class kmp_flag_64 : public kmp_basic_flag<kmp_uint64> {
434public:
435 kmp_flag_64(volatile kmp_uint64 *p) : kmp_basic_flag<kmp_uint64>(p) {}
436 kmp_flag_64(volatile kmp_uint64 *p, kmp_info_t *thr) : kmp_basic_flag<kmp_uint64>(p, thr) {}
437 kmp_flag_64(volatile kmp_uint64 *p, kmp_uint64 c) : kmp_basic_flag<kmp_uint64>(p, c) {}
438 void suspend(int th_gtid) { __kmp_suspend_64(th_gtid, this); }
439 void resume(int th_gtid) { __kmp_resume_64(th_gtid, this); }
440 int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin, int *thread_finished
441 USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained) {
442 return __kmp_execute_tasks_64(this_thr, gtid, this, final_spin, thread_finished
443 USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
444 }
445 void wait(kmp_info_t *this_thr, int final_spin
446 USE_ITT_BUILD_ARG(void * itt_sync_obj)) {
447 __kmp_wait_template(this_thr, this, final_spin
448 USE_ITT_BUILD_ARG(itt_sync_obj));
449 }
450 void release() { __kmp_release_template(this); }
451};
452
453// Hierarchical 64-bit on-core barrier instantiation
454class kmp_flag_oncore : public kmp_flag<kmp_uint64> {
455 kmp_uint64 checker;
456 kmp_info_t * waiting_threads[1];
457 kmp_uint32 num_waiting_threads;
458 kmp_uint32 offset; /**< Portion of flag that is of interest for an operation. */
459 bool flag_switch; /**< Indicates a switch in flag location. */
460 enum barrier_type bt; /**< Barrier type. */
461 kmp_info_t * this_thr; /**< Thread that may be redirected to different flag location. */
462#if USE_ITT_BUILD
463 void *itt_sync_obj; /**< ITT object that must be passed to new flag location. */
464#endif
Jonathan Peyton1e7a1dd2015-06-04 17:29:13 +0000465 unsigned char& byteref(volatile kmp_uint64* loc, size_t offset) { return ((unsigned char *)loc)[offset]; }
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000466public:
467 kmp_flag_oncore(volatile kmp_uint64 *p)
468 : kmp_flag<kmp_uint64>(p, flag_oncore), num_waiting_threads(0), flag_switch(false) {}
469 kmp_flag_oncore(volatile kmp_uint64 *p, kmp_uint32 idx)
Jonathan Peytonc98d0302015-06-03 17:26:47 +0000470 : kmp_flag<kmp_uint64>(p, flag_oncore), num_waiting_threads(0), offset(idx), flag_switch(false) {}
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000471 kmp_flag_oncore(volatile kmp_uint64 *p, kmp_uint64 c, kmp_uint32 idx, enum barrier_type bar_t,
472 kmp_info_t * thr
473#if USE_ITT_BUILD
474 , void *itt
475#endif
476 )
Jonathan Peytonc98d0302015-06-03 17:26:47 +0000477 : kmp_flag<kmp_uint64>(p, flag_oncore), checker(c), num_waiting_threads(0), offset(idx),
478 flag_switch(false), bt(bar_t), this_thr(thr)
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000479#if USE_ITT_BUILD
480 , itt_sync_obj(itt)
481#endif
Jonathan Peytonc98d0302015-06-03 17:26:47 +0000482 {}
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000483 kmp_info_t * get_waiter(kmp_uint32 i) {
484 KMP_DEBUG_ASSERT(i<num_waiting_threads);
485 return waiting_threads[i];
486 }
487 kmp_uint32 get_num_waiters() { return num_waiting_threads; }
488 void set_waiter(kmp_info_t *thr) {
489 waiting_threads[0] = thr;
490 num_waiting_threads = 1;
491 }
492 bool done_check_val(kmp_uint64 old_loc) { return byteref(&old_loc,offset) == checker; }
493 bool done_check() { return done_check_val(*get()); }
494 bool notdone_check() {
495 // Calculate flag_switch
496 if (this_thr->th.th_bar[bt].bb.wait_flag == KMP_BARRIER_SWITCH_TO_OWN_FLAG)
497 flag_switch = true;
498 if (byteref(get(),offset) != 1 && !flag_switch)
499 return true;
500 else if (flag_switch) {
501 this_thr->th.th_bar[bt].bb.wait_flag = KMP_BARRIER_SWITCHING;
502 kmp_flag_64 flag(&this_thr->th.th_bar[bt].bb.b_go, (kmp_uint64)KMP_BARRIER_STATE_BUMP);
503 __kmp_wait_64(this_thr, &flag, TRUE
504#if USE_ITT_BUILD
505 , itt_sync_obj
506#endif
507 );
508 }
509 return false;
510 }
511 kmp_uint64 internal_release() {
512 kmp_uint64 old_val;
513 if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME) {
514 old_val = *get();
515 byteref(get(),offset) = 1;
516 }
517 else {
518 kmp_uint64 mask=0;
519 byteref(&mask,offset) = 1;
520 old_val = KMP_TEST_THEN_OR64((volatile kmp_int64 *)get(), mask);
521 }
522 return old_val;
523 }
524 kmp_uint64 set_sleeping() {
525 return KMP_TEST_THEN_OR64((kmp_int64 volatile *)get(), KMP_BARRIER_SLEEP_STATE);
526 }
527 kmp_uint64 unset_sleeping() {
528 return KMP_TEST_THEN_AND64((kmp_int64 volatile *)get(), ~KMP_BARRIER_SLEEP_STATE);
529 }
530 bool is_sleeping_val(kmp_uint64 old_loc) { return old_loc & KMP_BARRIER_SLEEP_STATE; }
531 bool is_sleeping() { return is_sleeping_val(*get()); }
532 void wait(kmp_info_t *this_thr, int final_spin
533 USE_ITT_BUILD_ARG(void * itt_sync_obj)) {
534 __kmp_wait_template(this_thr, this, final_spin
535 USE_ITT_BUILD_ARG(itt_sync_obj));
536 }
537 void release() { __kmp_release_template(this); }
538 void suspend(int th_gtid) { __kmp_suspend_oncore(th_gtid, this); }
539 void resume(int th_gtid) { __kmp_resume_oncore(th_gtid, this); }
540 int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin, int *thread_finished
541 USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained) {
542 return __kmp_execute_tasks_oncore(this_thr, gtid, this, final_spin, thread_finished
543 USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
544 }
545};
546
547/*!
548@}
549*/
550
551#endif // KMP_WAIT_RELEASE_H