LLVM OpenMP* Runtime Library
kmp_wait_release.h
1 /*
2  * kmp_wait_release.h -- Wait/Release implementation
3  */
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 #include "kmp_stats.h"
22 
39 enum flag_type {
43 };
44 
48 template <typename P>
49 class kmp_flag {
50  volatile P * loc;
52  public:
53  typedef P flag_t;
54  kmp_flag(volatile P *p, flag_type ft) : loc(p), t(ft) {}
58  volatile P * get() { return loc; }
62  void set(volatile P *new_loc) { loc = new_loc; }
66  flag_type get_type() { return t; }
67  // Derived classes must provide the following:
68  /*
69  kmp_info_t * get_waiter(kmp_uint32 i);
70  kmp_uint32 get_num_waiters();
71  bool done_check();
72  bool done_check_val(P old_loc);
73  bool notdone_check();
74  P internal_release();
75  void suspend(int th_gtid);
76  void resume(int th_gtid);
77  P set_sleeping();
78  P unset_sleeping();
79  bool is_sleeping();
80  bool is_any_sleeping();
81  bool is_sleeping_val(P old_loc);
82  int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin, int *thread_finished
83  USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained);
84  */
85 };
86 
87 /* Spin wait loop that first does pause, then yield, then sleep. A thread that calls __kmp_wait_*
88  must make certain that another thread calls __kmp_release to wake it back up to prevent deadlocks! */
89 template <class C>
90 static inline void
91 __kmp_wait_template(kmp_info_t *this_thr, C *flag, int final_spin
92  USE_ITT_BUILD_ARG(void * itt_sync_obj) )
93 {
94  // NOTE: We may not belong to a team at this point.
95  volatile typename C::flag_t *spin = flag->get();
96  kmp_uint32 spins;
97  kmp_uint32 hibernate;
98  int th_gtid;
99  int tasks_completed = FALSE;
100  int oversubscribed;
101 
102  KMP_FSYNC_SPIN_INIT(spin, NULL);
103  if (flag->done_check()) {
104  KMP_FSYNC_SPIN_ACQUIRED(spin);
105  return;
106  }
107  th_gtid = this_thr->th.th_info.ds.ds_gtid;
108  KA_TRACE(20, ("__kmp_wait_sleep: T#%d waiting for flag(%p)\n", th_gtid, flag));
109 #if KMP_STATS_ENABLED
110  stats_state_e thread_state = KMP_GET_THREAD_STATE();
111 #endif
112 
113 #if OMPT_SUPPORT && OMPT_BLAME
114  ompt_state_t ompt_state = this_thr->th.ompt_thread_info.state;
115  if (ompt_enabled &&
116  ompt_state != ompt_state_undefined) {
117  if (ompt_state == ompt_state_idle) {
118  if (ompt_callbacks.ompt_callback(ompt_event_idle_begin)) {
119  ompt_callbacks.ompt_callback(ompt_event_idle_begin)(th_gtid + 1);
120  }
121  } else if (ompt_callbacks.ompt_callback(ompt_event_wait_barrier_begin)) {
122  KMP_DEBUG_ASSERT(ompt_state == ompt_state_wait_barrier ||
123  ompt_state == ompt_state_wait_barrier_implicit ||
124  ompt_state == ompt_state_wait_barrier_explicit);
125 
126  ompt_lw_taskteam_t* team = this_thr->th.th_team->t.ompt_serialized_team_info;
127  ompt_parallel_id_t pId;
128  ompt_task_id_t tId;
129  if (team){
130  pId = team->ompt_team_info.parallel_id;
131  tId = team->ompt_task_info.task_id;
132  } else {
133  pId = this_thr->th.th_team->t.ompt_team_info.parallel_id;
134  tId = this_thr->th.th_current_task->ompt_task_info.task_id;
135  }
136  ompt_callbacks.ompt_callback(ompt_event_wait_barrier_begin)(pId, tId);
137  }
138  }
139 #endif
140 
141  // Setup for waiting
142  KMP_INIT_YIELD(spins);
143 
144  if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
145  // The worker threads cannot rely on the team struct existing at this point.
146  // Use the bt values cached in the thread struct instead.
147 #ifdef KMP_ADJUST_BLOCKTIME
148  if (__kmp_zero_bt && !this_thr->th.th_team_bt_set)
149  // Force immediate suspend if not set by user and more threads than available procs
150  hibernate = 0;
151  else
152  hibernate = this_thr->th.th_team_bt_intervals;
153 #else
154  hibernate = this_thr->th.th_team_bt_intervals;
155 #endif /* KMP_ADJUST_BLOCKTIME */
156 
157  /* If the blocktime is nonzero, we want to make sure that we spin wait for the entirety
158  of the specified #intervals, plus up to one interval more. This increment make
159  certain that this thread doesn't go to sleep too soon. */
160  if (hibernate != 0)
161  hibernate++;
162 
163  // Add in the current time value.
164  hibernate += TCR_4(__kmp_global.g.g_time.dt.t_value);
165  KF_TRACE(20, ("__kmp_wait_sleep: T#%d now=%d, hibernate=%d, intervals=%d\n",
166  th_gtid, __kmp_global.g.g_time.dt.t_value, hibernate,
167  hibernate - __kmp_global.g.g_time.dt.t_value));
168  }
169 
170  oversubscribed = (TCR_4(__kmp_nth) > __kmp_avail_proc);
171  KMP_MB();
172 
173  // Main wait spin loop
174  while (flag->notdone_check()) {
175  int in_pool;
176  kmp_task_team_t * task_team = NULL;
177  if (__kmp_tasking_mode != tskm_immediate_exec) {
178  task_team = this_thr->th.th_task_team;
179  /* If the thread's task team pointer is NULL, it means one of 3 things:
180  1) A newly-created thread is first being released by __kmp_fork_barrier(), and
181  its task team has not been set up yet.
182  2) All tasks have been executed to completion.
183  3) Tasking is off for this region. This could be because we are in a serialized region
184  (perhaps the outer one), or else tasking was manually disabled (KMP_TASKING=0). */
185  if (task_team != NULL) {
186  if (TCR_SYNC_4(task_team->tt.tt_active)) {
187  if (KMP_TASKING_ENABLED(task_team))
188  flag->execute_tasks(this_thr, th_gtid, final_spin, &tasks_completed
189  USE_ITT_BUILD_ARG(itt_sync_obj), 0);
190  }
191  else {
192  KMP_DEBUG_ASSERT(!KMP_MASTER_TID(this_thr->th.th_info.ds.ds_tid));
193  this_thr->th.th_task_team = NULL;
194  }
195  } // if
196  } // if
197 
198  KMP_FSYNC_SPIN_PREPARE(spin);
199  if (TCR_4(__kmp_global.g.g_done)) {
200  if (__kmp_global.g.g_abort)
201  __kmp_abort_thread();
202  break;
203  }
204 
205  // If we are oversubscribed, or have waited a bit (and KMP_LIBRARY=throughput), then yield
206  KMP_YIELD(oversubscribed);
207  // TODO: Should it be number of cores instead of thread contexts? Like:
208  // KMP_YIELD(TCR_4(__kmp_nth) > __kmp_ncores);
209  // Need performance improvement data to make the change...
210  KMP_YIELD_SPIN(spins);
211 
212  // Check if this thread was transferred from a team
213  // to the thread pool (or vice-versa) while spinning.
214  in_pool = !!TCR_4(this_thr->th.th_in_pool);
215  if (in_pool != !!this_thr->th.th_active_in_pool) {
216  if (in_pool) { // Recently transferred from team to pool
217  KMP_TEST_THEN_INC32((kmp_int32 *)&__kmp_thread_pool_active_nth);
218  this_thr->th.th_active_in_pool = TRUE;
219  /* Here, we cannot assert that:
220  KMP_DEBUG_ASSERT(TCR_4(__kmp_thread_pool_active_nth) <= __kmp_thread_pool_nth);
221  __kmp_thread_pool_nth is inc/dec'd by the master thread while the fork/join
222  lock is held, whereas __kmp_thread_pool_active_nth is inc/dec'd asynchronously
223  by the workers. The two can get out of sync for brief periods of time. */
224  }
225  else { // Recently transferred from pool to team
226  KMP_TEST_THEN_DEC32((kmp_int32 *) &__kmp_thread_pool_active_nth);
227  KMP_DEBUG_ASSERT(TCR_4(__kmp_thread_pool_active_nth) >= 0);
228  this_thr->th.th_active_in_pool = FALSE;
229  }
230  }
231 
232 #if KMP_STATS_ENABLED
233  // Check if thread has been signalled to idle state
234  // This indicates that the logical "join-barrier" has finished
235  if (this_thr->th.th_stats->isIdle() && KMP_GET_THREAD_STATE() == FORK_JOIN_BARRIER) {
236  KMP_SET_THREAD_STATE(IDLE);
237  KMP_PUSH_PARTITIONED_TIMER(OMP_idle);
238  }
239 #endif
240 
241  // Don't suspend if KMP_BLOCKTIME is set to "infinite"
242  if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME)
243  continue;
244 
245  // Don't suspend if there is a likelihood of new tasks being spawned.
246  if ((task_team != NULL) && TCR_4(task_team->tt.tt_found_tasks))
247  continue;
248 
249  // If we have waited a bit more, fall asleep
250  if (TCR_4(__kmp_global.g.g_time.dt.t_value) < hibernate)
251  continue;
252 
253  KF_TRACE(50, ("__kmp_wait_sleep: T#%d suspend time reached\n", th_gtid));
254 
255  flag->suspend(th_gtid);
256 
257  if (TCR_4(__kmp_global.g.g_done)) {
258  if (__kmp_global.g.g_abort)
259  __kmp_abort_thread();
260  break;
261  }
262  // TODO: If thread is done with work and times out, disband/free
263  }
264 
265 #if OMPT_SUPPORT && OMPT_BLAME
266  if (ompt_enabled &&
267  ompt_state != ompt_state_undefined) {
268  if (ompt_state == ompt_state_idle) {
269  if (ompt_callbacks.ompt_callback(ompt_event_idle_end)) {
270  ompt_callbacks.ompt_callback(ompt_event_idle_end)(th_gtid + 1);
271  }
272  } else if (ompt_callbacks.ompt_callback(ompt_event_wait_barrier_end)) {
273  KMP_DEBUG_ASSERT(ompt_state == ompt_state_wait_barrier ||
274  ompt_state == ompt_state_wait_barrier_implicit ||
275  ompt_state == ompt_state_wait_barrier_explicit);
276 
277  ompt_lw_taskteam_t* team = this_thr->th.th_team->t.ompt_serialized_team_info;
278  ompt_parallel_id_t pId;
279  ompt_task_id_t tId;
280  if (team){
281  pId = team->ompt_team_info.parallel_id;
282  tId = team->ompt_task_info.task_id;
283  } else {
284  pId = this_thr->th.th_team->t.ompt_team_info.parallel_id;
285  tId = this_thr->th.th_current_task->ompt_task_info.task_id;
286  }
287  ompt_callbacks.ompt_callback(ompt_event_wait_barrier_end)(pId, tId);
288  }
289  }
290 #endif
291 #if KMP_STATS_ENABLED
292  // If we were put into idle state, pop that off the state stack
293  if (KMP_GET_THREAD_STATE() == IDLE) {
294  KMP_POP_PARTITIONED_TIMER();
295  KMP_SET_THREAD_STATE(thread_state);
296  this_thr->th.th_stats->resetIdleFlag();
297  }
298 #endif
299 
300  KMP_FSYNC_SPIN_ACQUIRED(spin);
301 }
302 
303 /* Release any threads specified as waiting on the flag by releasing the flag and resume the waiting thread
304  if indicated by the sleep bit(s). A thread that calls __kmp_wait_template must call this function to wake
305  up the potentially sleeping thread and prevent deadlocks! */
306 template <class C>
307 static inline void
308 __kmp_release_template(C *flag)
309 {
310 #ifdef KMP_DEBUG
311  int gtid = TCR_4(__kmp_init_gtid) ? __kmp_get_gtid() : -1;
312 #endif
313  KF_TRACE(20, ("__kmp_release: T#%d releasing flag(%x)\n", gtid, flag->get()));
314  KMP_DEBUG_ASSERT(flag->get());
315  KMP_FSYNC_RELEASING(flag->get());
316 
317  flag->internal_release();
318 
319  KF_TRACE(100, ("__kmp_release: T#%d set new spin=%d\n", gtid, flag->get(), *(flag->get())));
320 
321  if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
322  // Only need to check sleep stuff if infinite block time not set
323  if (flag->is_any_sleeping()) { // Are *any* of the threads that wait on this flag sleeping?
324  for (unsigned int i=0; i<flag->get_num_waiters(); ++i) {
325  kmp_info_t * waiter = flag->get_waiter(i); // if a sleeping waiter exists at i, sets current_waiter to i inside the flag
326  if (waiter) {
327  int wait_gtid = waiter->th.th_info.ds.ds_gtid;
328  // Wake up thread if needed
329  KF_TRACE(50, ("__kmp_release: T#%d waking up thread T#%d since sleep flag(%p) set\n",
330  gtid, wait_gtid, flag->get()));
331  flag->resume(wait_gtid); // unsets flag's current_waiter when done
332  }
333  }
334  }
335  }
336 }
337 
338 template <typename FlagType>
339 struct flag_traits {};
340 
341 template <>
342 struct flag_traits<kmp_uint32> {
343  typedef kmp_uint32 flag_t;
344  static const flag_type t = flag32;
345  static inline flag_t tcr(flag_t f) { return TCR_4(f); }
346  static inline flag_t test_then_add4(volatile flag_t *f) { return KMP_TEST_THEN_ADD4_32((volatile kmp_int32 *)f); }
347  static inline flag_t test_then_or(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_OR32((volatile kmp_int32 *)f, v); }
348  static inline flag_t test_then_and(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_AND32((volatile kmp_int32 *)f, v); }
349 };
350 
351 template <>
352 struct flag_traits<kmp_uint64> {
353  typedef kmp_uint64 flag_t;
354  static const flag_type t = flag64;
355  static inline flag_t tcr(flag_t f) { return TCR_8(f); }
356  static inline flag_t test_then_add4(volatile flag_t *f) { return KMP_TEST_THEN_ADD4_64((volatile kmp_int64 *)f); }
357  static inline flag_t test_then_or(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_OR64((volatile kmp_int64 *)f, v); }
358  static inline flag_t test_then_and(volatile flag_t *f, flag_t v) { return KMP_TEST_THEN_AND64((volatile kmp_int64 *)f, v); }
359 };
360 
361 template <typename FlagType>
362 class kmp_basic_flag : public kmp_flag<FlagType> {
363  typedef flag_traits<FlagType> traits_type;
364  FlagType checker;
365  kmp_info_t * waiting_threads[1];
366  kmp_uint32 num_waiting_threads;
367  public:
368  kmp_basic_flag(volatile FlagType *p) : kmp_flag<FlagType>(p, traits_type::t), num_waiting_threads(0) {}
369  kmp_basic_flag(volatile FlagType *p, kmp_info_t *thr) : kmp_flag<FlagType>(p, traits_type::t), num_waiting_threads(1) {
370  waiting_threads[0] = thr;
371  }
372  kmp_basic_flag(volatile FlagType *p, FlagType c) : kmp_flag<FlagType>(p, traits_type::t), checker(c), num_waiting_threads(0) {}
377  kmp_info_t * get_waiter(kmp_uint32 i) {
378  KMP_DEBUG_ASSERT(i<num_waiting_threads);
379  return waiting_threads[i];
380  }
384  kmp_uint32 get_num_waiters() { return num_waiting_threads; }
390  void set_waiter(kmp_info_t *thr) {
391  waiting_threads[0] = thr;
392  num_waiting_threads = 1;
393  }
397  bool done_check() { return traits_type::tcr(*(this->get())) == checker; }
402  bool done_check_val(FlagType old_loc) { return old_loc == checker; }
410  bool notdone_check() { return traits_type::tcr(*(this->get())) != checker; }
415  void internal_release() {
416  (void) traits_type::test_then_add4((volatile FlagType *)this->get());
417  }
422  FlagType set_sleeping() {
423  return traits_type::test_then_or((volatile FlagType *)this->get(), KMP_BARRIER_SLEEP_STATE);
424  }
429  FlagType unset_sleeping() {
430  return traits_type::test_then_and((volatile FlagType *)this->get(), ~KMP_BARRIER_SLEEP_STATE);
431  }
436  bool is_sleeping_val(FlagType old_loc) { return old_loc & KMP_BARRIER_SLEEP_STATE; }
440  bool is_sleeping() { return is_sleeping_val(*(this->get())); }
441  bool is_any_sleeping() { return is_sleeping_val(*(this->get())); }
442  kmp_uint8 *get_stolen() { return NULL; }
443  enum barrier_type get_bt() { return bs_last_barrier; }
444 };
445 
446 class kmp_flag_32 : public kmp_basic_flag<kmp_uint32> {
447  public:
448  kmp_flag_32(volatile kmp_uint32 *p) : kmp_basic_flag<kmp_uint32>(p) {}
449  kmp_flag_32(volatile kmp_uint32 *p, kmp_info_t *thr) : kmp_basic_flag<kmp_uint32>(p, thr) {}
450  kmp_flag_32(volatile kmp_uint32 *p, kmp_uint32 c) : kmp_basic_flag<kmp_uint32>(p, c) {}
451  void suspend(int th_gtid) { __kmp_suspend_32(th_gtid, this); }
452  void resume(int th_gtid) { __kmp_resume_32(th_gtid, this); }
453  int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin, int *thread_finished
454  USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained) {
455  return __kmp_execute_tasks_32(this_thr, gtid, this, final_spin, thread_finished
456  USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
457  }
458  void wait(kmp_info_t *this_thr, int final_spin
459  USE_ITT_BUILD_ARG(void * itt_sync_obj)) {
460  __kmp_wait_template(this_thr, this, final_spin
461  USE_ITT_BUILD_ARG(itt_sync_obj));
462  }
463  void release() { __kmp_release_template(this); }
464  flag_type get_ptr_type() { return flag32; }
465 };
466 
467 class kmp_flag_64 : public kmp_basic_flag<kmp_uint64> {
468  public:
469  kmp_flag_64(volatile kmp_uint64 *p) : kmp_basic_flag<kmp_uint64>(p) {}
470  kmp_flag_64(volatile kmp_uint64 *p, kmp_info_t *thr) : kmp_basic_flag<kmp_uint64>(p, thr) {}
471  kmp_flag_64(volatile kmp_uint64 *p, kmp_uint64 c) : kmp_basic_flag<kmp_uint64>(p, c) {}
472  void suspend(int th_gtid) { __kmp_suspend_64(th_gtid, this); }
473  void resume(int th_gtid) { __kmp_resume_64(th_gtid, this); }
474  int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin, int *thread_finished
475  USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained) {
476  return __kmp_execute_tasks_64(this_thr, gtid, this, final_spin, thread_finished
477  USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
478  }
479  void wait(kmp_info_t *this_thr, int final_spin
480  USE_ITT_BUILD_ARG(void * itt_sync_obj)) {
481  __kmp_wait_template(this_thr, this, final_spin
482  USE_ITT_BUILD_ARG(itt_sync_obj));
483  }
484  void release() { __kmp_release_template(this); }
485  flag_type get_ptr_type() { return flag64; }
486 };
487 
488 // Hierarchical 64-bit on-core barrier instantiation
489 class kmp_flag_oncore : public kmp_flag<kmp_uint64> {
490  kmp_uint64 checker;
491  kmp_info_t * waiting_threads[1];
492  kmp_uint32 num_waiting_threads;
493  kmp_uint32 offset;
494  bool flag_switch;
495  enum barrier_type bt;
496  kmp_info_t * this_thr;
497 #if USE_ITT_BUILD
498  void *itt_sync_obj;
499 #endif
500  unsigned char& byteref(volatile kmp_uint64* loc, size_t offset) { return ((unsigned char *)loc)[offset]; }
501 public:
502  kmp_flag_oncore(volatile kmp_uint64 *p)
503  : kmp_flag<kmp_uint64>(p, flag_oncore), num_waiting_threads(0), flag_switch(false) {}
504  kmp_flag_oncore(volatile kmp_uint64 *p, kmp_uint32 idx)
505  : kmp_flag<kmp_uint64>(p, flag_oncore), num_waiting_threads(0), offset(idx), flag_switch(false) {}
506  kmp_flag_oncore(volatile kmp_uint64 *p, kmp_uint64 c, kmp_uint32 idx, enum barrier_type bar_t,
507  kmp_info_t * thr
508 #if USE_ITT_BUILD
509  , void *itt
510 #endif
511  )
512  : kmp_flag<kmp_uint64>(p, flag_oncore), checker(c), num_waiting_threads(0), offset(idx),
513  flag_switch(false), bt(bar_t), this_thr(thr)
514 #if USE_ITT_BUILD
515  , itt_sync_obj(itt)
516 #endif
517  {}
518  kmp_info_t * get_waiter(kmp_uint32 i) {
519  KMP_DEBUG_ASSERT(i<num_waiting_threads);
520  return waiting_threads[i];
521  }
522  kmp_uint32 get_num_waiters() { return num_waiting_threads; }
523  void set_waiter(kmp_info_t *thr) {
524  waiting_threads[0] = thr;
525  num_waiting_threads = 1;
526  }
527  bool done_check_val(kmp_uint64 old_loc) { return byteref(&old_loc,offset) == checker; }
528  bool done_check() { return done_check_val(*get()); }
529  bool notdone_check() {
530  // Calculate flag_switch
531  if (this_thr->th.th_bar[bt].bb.wait_flag == KMP_BARRIER_SWITCH_TO_OWN_FLAG)
532  flag_switch = true;
533  if (byteref(get(),offset) != 1 && !flag_switch)
534  return true;
535  else if (flag_switch) {
536  this_thr->th.th_bar[bt].bb.wait_flag = KMP_BARRIER_SWITCHING;
537  kmp_flag_64 flag(&this_thr->th.th_bar[bt].bb.b_go, (kmp_uint64)KMP_BARRIER_STATE_BUMP);
538  __kmp_wait_64(this_thr, &flag, TRUE
539 #if USE_ITT_BUILD
540  , itt_sync_obj
541 #endif
542  );
543  }
544  return false;
545  }
546  void internal_release() {
547  if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME) {
548  byteref(get(),offset) = 1;
549  }
550  else {
551  kmp_uint64 mask=0;
552  byteref(&mask,offset) = 1;
553  (void) KMP_TEST_THEN_OR64((volatile kmp_int64 *)get(), mask);
554  }
555  }
556  kmp_uint64 set_sleeping() {
557  return KMP_TEST_THEN_OR64((kmp_int64 volatile *)get(), KMP_BARRIER_SLEEP_STATE);
558  }
559  kmp_uint64 unset_sleeping() {
560  return KMP_TEST_THEN_AND64((kmp_int64 volatile *)get(), ~KMP_BARRIER_SLEEP_STATE);
561  }
562  bool is_sleeping_val(kmp_uint64 old_loc) { return old_loc & KMP_BARRIER_SLEEP_STATE; }
563  bool is_sleeping() { return is_sleeping_val(*get()); }
564  bool is_any_sleeping() { return is_sleeping_val(*get()); }
565  void wait(kmp_info_t *this_thr, int final_spin) {
566  __kmp_wait_template<kmp_flag_oncore>(this_thr, this, final_spin
567  USE_ITT_BUILD_ARG(itt_sync_obj));
568  }
569  void release() { __kmp_release_template(this); }
570  void suspend(int th_gtid) { __kmp_suspend_oncore(th_gtid, this); }
571  void resume(int th_gtid) { __kmp_resume_oncore(th_gtid, this); }
572  int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin, int *thread_finished
573  USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained) {
574  return __kmp_execute_tasks_oncore(this_thr, gtid, this, final_spin, thread_finished
575  USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
576  }
577  kmp_uint8 *get_stolen() { return NULL; }
578  enum barrier_type get_bt() { return bt; }
579  flag_type get_ptr_type() { return flag_oncore; }
580 };
581 
582 // Used to wake up threads, volatile void* flag is usually the th_sleep_loc associated
583 // with int gtid.
584 static inline void __kmp_null_resume_wrapper(int gtid, volatile void *flag) {
585  if (!flag) return;
586 
587  switch (((kmp_flag_64 *)flag)->get_type()) {
588  case flag32: __kmp_resume_32(gtid, NULL); break;
589  case flag64: __kmp_resume_64(gtid, NULL); break;
590  case flag_oncore: __kmp_resume_oncore(gtid, NULL); break;
591  }
592 }
593 
598 #endif // KMP_WAIT_RELEASE_H
volatile P * loc
flag_type get_type()
flag_type
flag_type t
stats_state_e
the states which a thread can be in
Definition: kmp_stats.h:60