xref: /freebsd/contrib/llvm-project/openmp/runtime/src/kmp_wait_release.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric /*
20b57cec5SDimitry Andric  * kmp_wait_release.h -- Wait/Release implementation
30b57cec5SDimitry Andric  */
40b57cec5SDimitry Andric 
50b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
80b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
90b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #ifndef KMP_WAIT_RELEASE_H
140b57cec5SDimitry Andric #define KMP_WAIT_RELEASE_H
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "kmp.h"
170b57cec5SDimitry Andric #include "kmp_itt.h"
180b57cec5SDimitry Andric #include "kmp_stats.h"
190b57cec5SDimitry Andric #if OMPT_SUPPORT
200b57cec5SDimitry Andric #include "ompt-specific.h"
210b57cec5SDimitry Andric #endif
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric /*!
240b57cec5SDimitry Andric @defgroup WAIT_RELEASE Wait/Release operations
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric The definitions and functions here implement the lowest level thread
270b57cec5SDimitry Andric synchronizations of suspending a thread and awaking it. They are used to build
280b57cec5SDimitry Andric higher level operations such as barriers and fork/join.
290b57cec5SDimitry Andric */
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric /*!
320b57cec5SDimitry Andric @ingroup WAIT_RELEASE
330b57cec5SDimitry Andric @{
340b57cec5SDimitry Andric */
350b57cec5SDimitry Andric 
36e8d8bef9SDimitry Andric struct flag_properties {
37e8d8bef9SDimitry Andric   unsigned int type : 16;
38e8d8bef9SDimitry Andric   unsigned int reserved : 16;
39e8d8bef9SDimitry Andric };
40e8d8bef9SDimitry Andric 
41349cc55cSDimitry Andric template <enum flag_type FlagType> struct flag_traits {};
420b57cec5SDimitry Andric 
43349cc55cSDimitry Andric template <> struct flag_traits<flag32> {
44349cc55cSDimitry Andric   typedef kmp_uint32 flag_t;
45349cc55cSDimitry Andric   static const flag_type t = flag32;
46349cc55cSDimitry Andric   static inline flag_t tcr(flag_t f) { return TCR_4(f); }
47349cc55cSDimitry Andric   static inline flag_t test_then_add4(volatile flag_t *f) {
48349cc55cSDimitry Andric     return KMP_TEST_THEN_ADD4_32(RCAST(volatile kmp_int32 *, f));
49349cc55cSDimitry Andric   }
50349cc55cSDimitry Andric   static inline flag_t test_then_or(volatile flag_t *f, flag_t v) {
51349cc55cSDimitry Andric     return KMP_TEST_THEN_OR32(f, v);
52349cc55cSDimitry Andric   }
53349cc55cSDimitry Andric   static inline flag_t test_then_and(volatile flag_t *f, flag_t v) {
54349cc55cSDimitry Andric     return KMP_TEST_THEN_AND32(f, v);
55349cc55cSDimitry Andric   }
560b57cec5SDimitry Andric };
570b57cec5SDimitry Andric 
58349cc55cSDimitry Andric template <> struct flag_traits<atomic_flag64> {
59349cc55cSDimitry Andric   typedef kmp_uint64 flag_t;
60349cc55cSDimitry Andric   static const flag_type t = atomic_flag64;
61349cc55cSDimitry Andric   static inline flag_t tcr(flag_t f) { return TCR_8(f); }
62349cc55cSDimitry Andric   static inline flag_t test_then_add4(volatile flag_t *f) {
63349cc55cSDimitry Andric     return KMP_TEST_THEN_ADD4_64(RCAST(volatile kmp_int64 *, f));
64349cc55cSDimitry Andric   }
65349cc55cSDimitry Andric   static inline flag_t test_then_or(volatile flag_t *f, flag_t v) {
66349cc55cSDimitry Andric     return KMP_TEST_THEN_OR64(f, v);
67349cc55cSDimitry Andric   }
68349cc55cSDimitry Andric   static inline flag_t test_then_and(volatile flag_t *f, flag_t v) {
69349cc55cSDimitry Andric     return KMP_TEST_THEN_AND64(f, v);
70349cc55cSDimitry Andric   }
71349cc55cSDimitry Andric };
72349cc55cSDimitry Andric 
73349cc55cSDimitry Andric template <> struct flag_traits<flag64> {
74349cc55cSDimitry Andric   typedef kmp_uint64 flag_t;
75349cc55cSDimitry Andric   static const flag_type t = flag64;
76349cc55cSDimitry Andric   static inline flag_t tcr(flag_t f) { return TCR_8(f); }
77349cc55cSDimitry Andric   static inline flag_t test_then_add4(volatile flag_t *f) {
78349cc55cSDimitry Andric     return KMP_TEST_THEN_ADD4_64(RCAST(volatile kmp_int64 *, f));
79349cc55cSDimitry Andric   }
80349cc55cSDimitry Andric   static inline flag_t test_then_or(volatile flag_t *f, flag_t v) {
81349cc55cSDimitry Andric     return KMP_TEST_THEN_OR64(f, v);
82349cc55cSDimitry Andric   }
83349cc55cSDimitry Andric   static inline flag_t test_then_and(volatile flag_t *f, flag_t v) {
84349cc55cSDimitry Andric     return KMP_TEST_THEN_AND64(f, v);
85349cc55cSDimitry Andric   }
86349cc55cSDimitry Andric };
87349cc55cSDimitry Andric 
88349cc55cSDimitry Andric template <> struct flag_traits<flag_oncore> {
89349cc55cSDimitry Andric   typedef kmp_uint64 flag_t;
90349cc55cSDimitry Andric   static const flag_type t = flag_oncore;
91349cc55cSDimitry Andric   static inline flag_t tcr(flag_t f) { return TCR_8(f); }
92349cc55cSDimitry Andric   static inline flag_t test_then_add4(volatile flag_t *f) {
93349cc55cSDimitry Andric     return KMP_TEST_THEN_ADD4_64(RCAST(volatile kmp_int64 *, f));
94349cc55cSDimitry Andric   }
95349cc55cSDimitry Andric   static inline flag_t test_then_or(volatile flag_t *f, flag_t v) {
96349cc55cSDimitry Andric     return KMP_TEST_THEN_OR64(f, v);
97349cc55cSDimitry Andric   }
98349cc55cSDimitry Andric   static inline flag_t test_then_and(volatile flag_t *f, flag_t v) {
99349cc55cSDimitry Andric     return KMP_TEST_THEN_AND64(f, v);
100349cc55cSDimitry Andric   }
101349cc55cSDimitry Andric };
102349cc55cSDimitry Andric 
103349cc55cSDimitry Andric /*! Base class for all flags */
104349cc55cSDimitry Andric template <flag_type FlagType> class kmp_flag {
105349cc55cSDimitry Andric protected:
106e8d8bef9SDimitry Andric   flag_properties t; /**< "Type" of the flag in loc */
107349cc55cSDimitry Andric   kmp_info_t *waiting_threads[1]; /**< Threads sleeping on this thread. */
10881ad6265SDimitry Andric   kmp_uint32 num_waiting_threads; /**< Num threads sleeping on this thread. */
109349cc55cSDimitry Andric   std::atomic<bool> *sleepLoc;
110349cc55cSDimitry Andric 
1110b57cec5SDimitry Andric public:
112349cc55cSDimitry Andric   typedef flag_traits<FlagType> traits_type;
113349cc55cSDimitry Andric   kmp_flag() : t({FlagType, 0U}), num_waiting_threads(0), sleepLoc(nullptr) {}
114349cc55cSDimitry Andric   kmp_flag(int nwaiters)
115349cc55cSDimitry Andric       : t({FlagType, 0U}), num_waiting_threads(nwaiters), sleepLoc(nullptr) {}
116349cc55cSDimitry Andric   kmp_flag(std::atomic<bool> *sloc)
117349cc55cSDimitry Andric       : t({FlagType, 0U}), num_waiting_threads(0), sleepLoc(sloc) {}
118349cc55cSDimitry Andric   /*! @result the flag_type */
119e8d8bef9SDimitry Andric   flag_type get_type() { return (flag_type)(t.type); }
120349cc55cSDimitry Andric 
121349cc55cSDimitry Andric   /*! param i in   index into waiting_threads
122349cc55cSDimitry Andric    *  @result the thread that is waiting at index i */
123349cc55cSDimitry Andric   kmp_info_t *get_waiter(kmp_uint32 i) {
124349cc55cSDimitry Andric     KMP_DEBUG_ASSERT(i < num_waiting_threads);
125349cc55cSDimitry Andric     return waiting_threads[i];
126349cc55cSDimitry Andric   }
127349cc55cSDimitry Andric   /*! @result num_waiting_threads */
128349cc55cSDimitry Andric   kmp_uint32 get_num_waiters() { return num_waiting_threads; }
129349cc55cSDimitry Andric   /*! @param thr in   the thread which is now waiting
130349cc55cSDimitry Andric    *  Insert a waiting thread at index 0. */
131349cc55cSDimitry Andric   void set_waiter(kmp_info_t *thr) {
132349cc55cSDimitry Andric     waiting_threads[0] = thr;
133349cc55cSDimitry Andric     num_waiting_threads = 1;
134349cc55cSDimitry Andric   }
135349cc55cSDimitry Andric   enum barrier_type get_bt() { return bs_last_barrier; }
136349cc55cSDimitry Andric };
137349cc55cSDimitry Andric 
138349cc55cSDimitry Andric /*! Base class for wait/release volatile flag */
139349cc55cSDimitry Andric template <typename PtrType, flag_type FlagType, bool Sleepable>
140349cc55cSDimitry Andric class kmp_flag_native : public kmp_flag<FlagType> {
141349cc55cSDimitry Andric protected:
142349cc55cSDimitry Andric   volatile PtrType *loc;
143349cc55cSDimitry Andric   PtrType checker; /**< When flag==checker, it has been released. */
144349cc55cSDimitry Andric   typedef flag_traits<FlagType> traits_type;
145349cc55cSDimitry Andric 
146349cc55cSDimitry Andric public:
147349cc55cSDimitry Andric   typedef PtrType flag_t;
148349cc55cSDimitry Andric   kmp_flag_native(volatile PtrType *p) : kmp_flag<FlagType>(), loc(p) {}
149349cc55cSDimitry Andric   kmp_flag_native(volatile PtrType *p, kmp_info_t *thr)
150349cc55cSDimitry Andric       : kmp_flag<FlagType>(1), loc(p) {
151349cc55cSDimitry Andric     this->waiting_threads[0] = thr;
152349cc55cSDimitry Andric   }
153349cc55cSDimitry Andric   kmp_flag_native(volatile PtrType *p, PtrType c)
154349cc55cSDimitry Andric       : kmp_flag<FlagType>(), loc(p), checker(c) {}
155349cc55cSDimitry Andric   kmp_flag_native(volatile PtrType *p, PtrType c, std::atomic<bool> *sloc)
156349cc55cSDimitry Andric       : kmp_flag<FlagType>(sloc), loc(p), checker(c) {}
157349cc55cSDimitry Andric   virtual ~kmp_flag_native() {}
158349cc55cSDimitry Andric   void *operator new(size_t size) { return __kmp_allocate(size); }
159349cc55cSDimitry Andric   void operator delete(void *p) { __kmp_free(p); }
160349cc55cSDimitry Andric   volatile PtrType *get() { return loc; }
161349cc55cSDimitry Andric   void *get_void_p() { return RCAST(void *, CCAST(PtrType *, loc)); }
162349cc55cSDimitry Andric   void set(volatile PtrType *new_loc) { loc = new_loc; }
163349cc55cSDimitry Andric   PtrType load() { return *loc; }
164349cc55cSDimitry Andric   void store(PtrType val) { *loc = val; }
165349cc55cSDimitry Andric   /*! @result true if the flag object has been released. */
166349cc55cSDimitry Andric   virtual bool done_check() {
167349cc55cSDimitry Andric     if (Sleepable && !(this->sleepLoc))
168349cc55cSDimitry Andric       return (traits_type::tcr(*(this->get())) & ~KMP_BARRIER_SLEEP_STATE) ==
169349cc55cSDimitry Andric              checker;
170349cc55cSDimitry Andric     else
171349cc55cSDimitry Andric       return traits_type::tcr(*(this->get())) == checker;
172349cc55cSDimitry Andric   }
173349cc55cSDimitry Andric   /*! @param old_loc in   old value of flag
174349cc55cSDimitry Andric    *  @result true if the flag's old value indicates it was released. */
175349cc55cSDimitry Andric   virtual bool done_check_val(PtrType old_loc) { return old_loc == checker; }
176349cc55cSDimitry Andric   /*! @result true if the flag object is not yet released.
177349cc55cSDimitry Andric    * Used in __kmp_wait_template like:
178349cc55cSDimitry Andric    * @code
179349cc55cSDimitry Andric    * while (flag.notdone_check()) { pause(); }
180349cc55cSDimitry Andric    * @endcode */
181349cc55cSDimitry Andric   virtual bool notdone_check() {
182349cc55cSDimitry Andric     return traits_type::tcr(*(this->get())) != checker;
183349cc55cSDimitry Andric   }
184349cc55cSDimitry Andric   /*! @result Actual flag value before release was applied.
185349cc55cSDimitry Andric    * Trigger all waiting threads to run by modifying flag to release state. */
186349cc55cSDimitry Andric   void internal_release() {
187349cc55cSDimitry Andric     (void)traits_type::test_then_add4((volatile PtrType *)this->get());
188349cc55cSDimitry Andric   }
189349cc55cSDimitry Andric   /*! @result Actual flag value before sleep bit(s) set.
190349cc55cSDimitry Andric    * Notes that there is at least one thread sleeping on the flag by setting
191349cc55cSDimitry Andric    * sleep bit(s). */
192349cc55cSDimitry Andric   PtrType set_sleeping() {
193349cc55cSDimitry Andric     if (this->sleepLoc) {
194349cc55cSDimitry Andric       this->sleepLoc->store(true);
195349cc55cSDimitry Andric       return *(this->get());
196349cc55cSDimitry Andric     }
197349cc55cSDimitry Andric     return traits_type::test_then_or((volatile PtrType *)this->get(),
198349cc55cSDimitry Andric                                      KMP_BARRIER_SLEEP_STATE);
199349cc55cSDimitry Andric   }
200349cc55cSDimitry Andric   /*! @result Actual flag value before sleep bit(s) cleared.
201349cc55cSDimitry Andric    * Notes that there are no longer threads sleeping on the flag by clearing
202349cc55cSDimitry Andric    * sleep bit(s). */
203349cc55cSDimitry Andric   void unset_sleeping() {
204349cc55cSDimitry Andric     if (this->sleepLoc) {
205349cc55cSDimitry Andric       this->sleepLoc->store(false);
206349cc55cSDimitry Andric       return;
207349cc55cSDimitry Andric     }
208349cc55cSDimitry Andric     traits_type::test_then_and((volatile PtrType *)this->get(),
209349cc55cSDimitry Andric                                ~KMP_BARRIER_SLEEP_STATE);
210349cc55cSDimitry Andric   }
211349cc55cSDimitry Andric   /*! @param old_loc in   old value of flag
212349cc55cSDimitry Andric    * Test if there are threads sleeping on the flag's old value in old_loc. */
213349cc55cSDimitry Andric   bool is_sleeping_val(PtrType old_loc) {
214349cc55cSDimitry Andric     if (this->sleepLoc)
215349cc55cSDimitry Andric       return this->sleepLoc->load();
216349cc55cSDimitry Andric     return old_loc & KMP_BARRIER_SLEEP_STATE;
217349cc55cSDimitry Andric   }
218349cc55cSDimitry Andric   /*! Test whether there are threads sleeping on the flag. */
219349cc55cSDimitry Andric   bool is_sleeping() {
220349cc55cSDimitry Andric     if (this->sleepLoc)
221349cc55cSDimitry Andric       return this->sleepLoc->load();
222349cc55cSDimitry Andric     return is_sleeping_val(*(this->get()));
223349cc55cSDimitry Andric   }
224349cc55cSDimitry Andric   bool is_any_sleeping() {
225349cc55cSDimitry Andric     if (this->sleepLoc)
226349cc55cSDimitry Andric       return this->sleepLoc->load();
227349cc55cSDimitry Andric     return is_sleeping_val(*(this->get()));
228349cc55cSDimitry Andric   }
229349cc55cSDimitry Andric   kmp_uint8 *get_stolen() { return NULL; }
230349cc55cSDimitry Andric };
231349cc55cSDimitry Andric 
232349cc55cSDimitry Andric /*! Base class for wait/release atomic flag */
233349cc55cSDimitry Andric template <typename PtrType, flag_type FlagType, bool Sleepable>
234349cc55cSDimitry Andric class kmp_flag_atomic : public kmp_flag<FlagType> {
235349cc55cSDimitry Andric protected:
236349cc55cSDimitry Andric   std::atomic<PtrType> *loc; /**< Pointer to flag location to wait on */
237349cc55cSDimitry Andric   PtrType checker; /**< Flag == checker means it has been released. */
238349cc55cSDimitry Andric public:
239349cc55cSDimitry Andric   typedef flag_traits<FlagType> traits_type;
240349cc55cSDimitry Andric   typedef PtrType flag_t;
241349cc55cSDimitry Andric   kmp_flag_atomic(std::atomic<PtrType> *p) : kmp_flag<FlagType>(), loc(p) {}
242349cc55cSDimitry Andric   kmp_flag_atomic(std::atomic<PtrType> *p, kmp_info_t *thr)
243349cc55cSDimitry Andric       : kmp_flag<FlagType>(1), loc(p) {
244349cc55cSDimitry Andric     this->waiting_threads[0] = thr;
245349cc55cSDimitry Andric   }
246349cc55cSDimitry Andric   kmp_flag_atomic(std::atomic<PtrType> *p, PtrType c)
247349cc55cSDimitry Andric       : kmp_flag<FlagType>(), loc(p), checker(c) {}
248349cc55cSDimitry Andric   kmp_flag_atomic(std::atomic<PtrType> *p, PtrType c, std::atomic<bool> *sloc)
249349cc55cSDimitry Andric       : kmp_flag<FlagType>(sloc), loc(p), checker(c) {}
250349cc55cSDimitry Andric   /*! @result the pointer to the actual flag */
251349cc55cSDimitry Andric   std::atomic<PtrType> *get() { return loc; }
252349cc55cSDimitry Andric   /*! @result void* pointer to the actual flag */
253349cc55cSDimitry Andric   void *get_void_p() { return RCAST(void *, loc); }
254349cc55cSDimitry Andric   /*! @param new_loc in   set loc to point at new_loc */
255349cc55cSDimitry Andric   void set(std::atomic<PtrType> *new_loc) { loc = new_loc; }
256349cc55cSDimitry Andric   /*! @result flag value */
257349cc55cSDimitry Andric   PtrType load() { return loc->load(std::memory_order_acquire); }
258349cc55cSDimitry Andric   /*! @param val the new flag value to be stored */
259349cc55cSDimitry Andric   void store(PtrType val) { loc->store(val, std::memory_order_release); }
260349cc55cSDimitry Andric   /*! @result true if the flag object has been released. */
261349cc55cSDimitry Andric   bool done_check() {
262349cc55cSDimitry Andric     if (Sleepable && !(this->sleepLoc))
263349cc55cSDimitry Andric       return (this->load() & ~KMP_BARRIER_SLEEP_STATE) == checker;
264349cc55cSDimitry Andric     else
265349cc55cSDimitry Andric       return this->load() == checker;
266349cc55cSDimitry Andric   }
267349cc55cSDimitry Andric   /*! @param old_loc in   old value of flag
268349cc55cSDimitry Andric    * @result true if the flag's old value indicates it was released. */
269349cc55cSDimitry Andric   bool done_check_val(PtrType old_loc) { return old_loc == checker; }
270349cc55cSDimitry Andric   /*! @result true if the flag object is not yet released.
271349cc55cSDimitry Andric    * Used in __kmp_wait_template like:
272349cc55cSDimitry Andric    * @code
273349cc55cSDimitry Andric    * while (flag.notdone_check()) { pause(); }
274349cc55cSDimitry Andric    * @endcode */
275349cc55cSDimitry Andric   bool notdone_check() { return this->load() != checker; }
276349cc55cSDimitry Andric   /*! @result Actual flag value before release was applied.
277349cc55cSDimitry Andric    * Trigger all waiting threads to run by modifying flag to release state. */
278349cc55cSDimitry Andric   void internal_release() { KMP_ATOMIC_ADD(this->get(), 4); }
279349cc55cSDimitry Andric   /*! @result Actual flag value before sleep bit(s) set.
280349cc55cSDimitry Andric    * Notes that there is at least one thread sleeping on the flag by setting
281349cc55cSDimitry Andric    * sleep bit(s). */
282349cc55cSDimitry Andric   PtrType set_sleeping() {
283349cc55cSDimitry Andric     if (this->sleepLoc) {
284349cc55cSDimitry Andric       this->sleepLoc->store(true);
285349cc55cSDimitry Andric       return *(this->get());
286349cc55cSDimitry Andric     }
287349cc55cSDimitry Andric     return KMP_ATOMIC_OR(this->get(), KMP_BARRIER_SLEEP_STATE);
288349cc55cSDimitry Andric   }
289349cc55cSDimitry Andric   /*! @result Actual flag value before sleep bit(s) cleared.
290349cc55cSDimitry Andric    * Notes that there are no longer threads sleeping on the flag by clearing
291349cc55cSDimitry Andric    * sleep bit(s). */
292349cc55cSDimitry Andric   void unset_sleeping() {
293349cc55cSDimitry Andric     if (this->sleepLoc) {
294349cc55cSDimitry Andric       this->sleepLoc->store(false);
295349cc55cSDimitry Andric       return;
296349cc55cSDimitry Andric     }
297349cc55cSDimitry Andric     KMP_ATOMIC_AND(this->get(), ~KMP_BARRIER_SLEEP_STATE);
298349cc55cSDimitry Andric   }
299349cc55cSDimitry Andric   /*! @param old_loc in   old value of flag
300349cc55cSDimitry Andric    * Test whether there are threads sleeping on flag's old value in old_loc. */
301349cc55cSDimitry Andric   bool is_sleeping_val(PtrType old_loc) {
302349cc55cSDimitry Andric     if (this->sleepLoc)
303349cc55cSDimitry Andric       return this->sleepLoc->load();
304349cc55cSDimitry Andric     return old_loc & KMP_BARRIER_SLEEP_STATE;
305349cc55cSDimitry Andric   }
306349cc55cSDimitry Andric   /*! Test whether there are threads sleeping on the flag. */
307349cc55cSDimitry Andric   bool is_sleeping() {
308349cc55cSDimitry Andric     if (this->sleepLoc)
309349cc55cSDimitry Andric       return this->sleepLoc->load();
310349cc55cSDimitry Andric     return is_sleeping_val(this->load());
311349cc55cSDimitry Andric   }
312349cc55cSDimitry Andric   bool is_any_sleeping() {
313349cc55cSDimitry Andric     if (this->sleepLoc)
314349cc55cSDimitry Andric       return this->sleepLoc->load();
315349cc55cSDimitry Andric     return is_sleeping_val(this->load());
316349cc55cSDimitry Andric   }
317349cc55cSDimitry Andric   kmp_uint8 *get_stolen() { return NULL; }
3180b57cec5SDimitry Andric };
3190b57cec5SDimitry Andric 
3200b57cec5SDimitry Andric #if OMPT_SUPPORT
3210b57cec5SDimitry Andric OMPT_NOINLINE
3220b57cec5SDimitry Andric static void __ompt_implicit_task_end(kmp_info_t *this_thr,
3230b57cec5SDimitry Andric                                      ompt_state_t ompt_state,
3240b57cec5SDimitry Andric                                      ompt_data_t *tId) {
3250b57cec5SDimitry Andric   int ds_tid = this_thr->th.th_info.ds.ds_tid;
326*0fca6ea1SDimitry Andric   if (ompt_state == ompt_state_wait_barrier_implicit_parallel ||
327*0fca6ea1SDimitry Andric       ompt_state == ompt_state_wait_barrier_teams) {
3280b57cec5SDimitry Andric     this_thr->th.ompt_thread_info.state = ompt_state_overhead;
3290b57cec5SDimitry Andric #if OMPT_OPTIONAL
3300b57cec5SDimitry Andric     void *codeptr = NULL;
331*0fca6ea1SDimitry Andric     ompt_sync_region_t sync_kind = ompt_sync_region_barrier_implicit_parallel;
332*0fca6ea1SDimitry Andric     if (this_thr->th.ompt_thread_info.parallel_flags & ompt_parallel_league)
333*0fca6ea1SDimitry Andric       sync_kind = ompt_sync_region_barrier_teams;
3340b57cec5SDimitry Andric     if (ompt_enabled.ompt_callback_sync_region_wait) {
3350b57cec5SDimitry Andric       ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
336*0fca6ea1SDimitry Andric           sync_kind, ompt_scope_end, NULL, tId, codeptr);
3370b57cec5SDimitry Andric     }
3380b57cec5SDimitry Andric     if (ompt_enabled.ompt_callback_sync_region) {
3390b57cec5SDimitry Andric       ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
340*0fca6ea1SDimitry Andric           sync_kind, ompt_scope_end, NULL, tId, codeptr);
3410b57cec5SDimitry Andric     }
3420b57cec5SDimitry Andric #endif
3430b57cec5SDimitry Andric     if (!KMP_MASTER_TID(ds_tid)) {
3440b57cec5SDimitry Andric       if (ompt_enabled.ompt_callback_implicit_task) {
345489b1cf2SDimitry Andric         int flags = this_thr->th.ompt_thread_info.parallel_flags;
346489b1cf2SDimitry Andric         flags = (flags & ompt_parallel_league) ? ompt_task_initial
347489b1cf2SDimitry Andric                                                : ompt_task_implicit;
3480b57cec5SDimitry Andric         ompt_callbacks.ompt_callback(ompt_callback_implicit_task)(
349489b1cf2SDimitry Andric             ompt_scope_end, NULL, tId, 0, ds_tid, flags);
3500b57cec5SDimitry Andric       }
3510b57cec5SDimitry Andric       // return to idle state
3520b57cec5SDimitry Andric       this_thr->th.ompt_thread_info.state = ompt_state_idle;
3530b57cec5SDimitry Andric     } else {
3540b57cec5SDimitry Andric       this_thr->th.ompt_thread_info.state = ompt_state_overhead;
3550b57cec5SDimitry Andric     }
3560b57cec5SDimitry Andric   }
3570b57cec5SDimitry Andric }
3580b57cec5SDimitry Andric #endif
3590b57cec5SDimitry Andric 
3600b57cec5SDimitry Andric /* Spin wait loop that first does pause/yield, then sleep. A thread that calls
3610b57cec5SDimitry Andric    __kmp_wait_*  must make certain that another thread calls __kmp_release
3620b57cec5SDimitry Andric    to wake it back up to prevent deadlocks!
3630b57cec5SDimitry Andric 
3640b57cec5SDimitry Andric    NOTE: We may not belong to a team at this point.  */
365e8d8bef9SDimitry Andric template <class C, bool final_spin, bool Cancellable = false,
366e8d8bef9SDimitry Andric           bool Sleepable = true>
3670b57cec5SDimitry Andric static inline bool
3680b57cec5SDimitry Andric __kmp_wait_template(kmp_info_t *this_thr,
3690b57cec5SDimitry Andric                     C *flag USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
3700b57cec5SDimitry Andric #if USE_ITT_BUILD && USE_ITT_NOTIFY
3710b57cec5SDimitry Andric   volatile void *spin = flag->get();
3720b57cec5SDimitry Andric #endif
3730b57cec5SDimitry Andric   kmp_uint32 spins;
3740b57cec5SDimitry Andric   int th_gtid;
3750b57cec5SDimitry Andric   int tasks_completed = FALSE;
3760b57cec5SDimitry Andric #if !KMP_USE_MONITOR
3770b57cec5SDimitry Andric   kmp_uint64 poll_count;
3780b57cec5SDimitry Andric   kmp_uint64 hibernate_goal;
3790b57cec5SDimitry Andric #else
3800b57cec5SDimitry Andric   kmp_uint32 hibernate;
3810b57cec5SDimitry Andric #endif
38204eeddc0SDimitry Andric   kmp_uint64 time;
3830b57cec5SDimitry Andric 
3840b57cec5SDimitry Andric   KMP_FSYNC_SPIN_INIT(spin, NULL);
3850b57cec5SDimitry Andric   if (flag->done_check()) {
3860b57cec5SDimitry Andric     KMP_FSYNC_SPIN_ACQUIRED(CCAST(void *, spin));
3870b57cec5SDimitry Andric     return false;
3880b57cec5SDimitry Andric   }
3890b57cec5SDimitry Andric   th_gtid = this_thr->th.th_info.ds.ds_gtid;
390e8d8bef9SDimitry Andric   if (Cancellable) {
3910b57cec5SDimitry Andric     kmp_team_t *team = this_thr->th.th_team;
3920b57cec5SDimitry Andric     if (team && team->t.t_cancel_request == cancel_parallel)
3930b57cec5SDimitry Andric       return true;
3940b57cec5SDimitry Andric   }
3950b57cec5SDimitry Andric #if KMP_OS_UNIX
3960b57cec5SDimitry Andric   if (final_spin)
3970b57cec5SDimitry Andric     KMP_ATOMIC_ST_REL(&this_thr->th.th_blocking, true);
3980b57cec5SDimitry Andric #endif
3990b57cec5SDimitry Andric   KA_TRACE(20,
4000b57cec5SDimitry Andric            ("__kmp_wait_sleep: T#%d waiting for flag(%p)\n", th_gtid, flag));
4010b57cec5SDimitry Andric #if KMP_STATS_ENABLED
4020b57cec5SDimitry Andric   stats_state_e thread_state = KMP_GET_THREAD_STATE();
4030b57cec5SDimitry Andric #endif
4040b57cec5SDimitry Andric 
4050b57cec5SDimitry Andric /* OMPT Behavior:
4060b57cec5SDimitry Andric THIS function is called from
4070b57cec5SDimitry Andric   __kmp_barrier (2 times)  (implicit or explicit barrier in parallel regions)
4080b57cec5SDimitry Andric             these have join / fork behavior
4090b57cec5SDimitry Andric 
4100b57cec5SDimitry Andric        In these cases, we don't change the state or trigger events in THIS
4110b57cec5SDimitry Andric function.
4120b57cec5SDimitry Andric        Events are triggered in the calling code (__kmp_barrier):
4130b57cec5SDimitry Andric 
4140b57cec5SDimitry Andric                 state := ompt_state_overhead
4150b57cec5SDimitry Andric             barrier-begin
4160b57cec5SDimitry Andric             barrier-wait-begin
4170b57cec5SDimitry Andric                 state := ompt_state_wait_barrier
4180b57cec5SDimitry Andric           call join-barrier-implementation (finally arrive here)
4190b57cec5SDimitry Andric           {}
4200b57cec5SDimitry Andric           call fork-barrier-implementation (finally arrive here)
4210b57cec5SDimitry Andric           {}
4220b57cec5SDimitry Andric                 state := ompt_state_overhead
4230b57cec5SDimitry Andric             barrier-wait-end
4240b57cec5SDimitry Andric             barrier-end
4250b57cec5SDimitry Andric                 state := ompt_state_work_parallel
4260b57cec5SDimitry Andric 
4270b57cec5SDimitry Andric 
4280b57cec5SDimitry Andric   __kmp_fork_barrier  (after thread creation, before executing implicit task)
4290b57cec5SDimitry Andric           call fork-barrier-implementation (finally arrive here)
4300b57cec5SDimitry Andric           {} // worker arrive here with state = ompt_state_idle
4310b57cec5SDimitry Andric 
4320b57cec5SDimitry Andric 
4330b57cec5SDimitry Andric   __kmp_join_barrier  (implicit barrier at end of parallel region)
4340b57cec5SDimitry Andric                 state := ompt_state_barrier_implicit
4350b57cec5SDimitry Andric             barrier-begin
4360b57cec5SDimitry Andric             barrier-wait-begin
4370b57cec5SDimitry Andric           call join-barrier-implementation (finally arrive here
4380b57cec5SDimitry Andric final_spin=FALSE)
4390b57cec5SDimitry Andric           {
4400b57cec5SDimitry Andric           }
4410b57cec5SDimitry Andric   __kmp_fork_barrier  (implicit barrier at end of parallel region)
4420b57cec5SDimitry Andric           call fork-barrier-implementation (finally arrive here final_spin=TRUE)
4430b57cec5SDimitry Andric 
4440b57cec5SDimitry Andric        Worker after task-team is finished:
4450b57cec5SDimitry Andric             barrier-wait-end
4460b57cec5SDimitry Andric             barrier-end
4470b57cec5SDimitry Andric             implicit-task-end
4480b57cec5SDimitry Andric             idle-begin
4490b57cec5SDimitry Andric                 state := ompt_state_idle
4500b57cec5SDimitry Andric 
4510b57cec5SDimitry Andric        Before leaving, if state = ompt_state_idle
4520b57cec5SDimitry Andric             idle-end
4530b57cec5SDimitry Andric                 state := ompt_state_overhead
4540b57cec5SDimitry Andric */
4550b57cec5SDimitry Andric #if OMPT_SUPPORT
4560b57cec5SDimitry Andric   ompt_state_t ompt_entry_state;
4570b57cec5SDimitry Andric   ompt_data_t *tId;
4580b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
4590b57cec5SDimitry Andric     ompt_entry_state = this_thr->th.ompt_thread_info.state;
460*0fca6ea1SDimitry Andric     if (!final_spin ||
461*0fca6ea1SDimitry Andric         (ompt_entry_state != ompt_state_wait_barrier_implicit_parallel &&
462*0fca6ea1SDimitry Andric          ompt_entry_state != ompt_state_wait_barrier_teams) ||
4630b57cec5SDimitry Andric         KMP_MASTER_TID(this_thr->th.th_info.ds.ds_tid)) {
464349cc55cSDimitry Andric       ompt_lw_taskteam_t *team = NULL;
465349cc55cSDimitry Andric       if (this_thr->th.th_team)
466349cc55cSDimitry Andric         team = this_thr->th.th_team->t.ompt_serialized_team_info;
4670b57cec5SDimitry Andric       if (team) {
4680b57cec5SDimitry Andric         tId = &(team->ompt_task_info.task_data);
4690b57cec5SDimitry Andric       } else {
4700b57cec5SDimitry Andric         tId = OMPT_CUR_TASK_DATA(this_thr);
4710b57cec5SDimitry Andric       }
4720b57cec5SDimitry Andric     } else {
4730b57cec5SDimitry Andric       tId = &(this_thr->th.ompt_thread_info.task_data);
4740b57cec5SDimitry Andric     }
4750b57cec5SDimitry Andric     if (final_spin && (__kmp_tasking_mode == tskm_immediate_exec ||
4760b57cec5SDimitry Andric                        this_thr->th.th_task_team == NULL)) {
4770b57cec5SDimitry Andric       // implicit task is done. Either no taskqueue, or task-team finished
4780b57cec5SDimitry Andric       __ompt_implicit_task_end(this_thr, ompt_entry_state, tId);
4790b57cec5SDimitry Andric     }
4800b57cec5SDimitry Andric   }
4810b57cec5SDimitry Andric #endif
4820b57cec5SDimitry Andric 
4830b57cec5SDimitry Andric   KMP_INIT_YIELD(spins); // Setup for waiting
48404eeddc0SDimitry Andric   KMP_INIT_BACKOFF(time);
4850b57cec5SDimitry Andric 
4860b57cec5SDimitry Andric   if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME ||
4870b57cec5SDimitry Andric       __kmp_pause_status == kmp_soft_paused) {
4880b57cec5SDimitry Andric #if KMP_USE_MONITOR
4890b57cec5SDimitry Andric // The worker threads cannot rely on the team struct existing at this point.
4900b57cec5SDimitry Andric // Use the bt values cached in the thread struct instead.
4910b57cec5SDimitry Andric #ifdef KMP_ADJUST_BLOCKTIME
4920b57cec5SDimitry Andric     if (__kmp_pause_status == kmp_soft_paused ||
4930b57cec5SDimitry Andric         (__kmp_zero_bt && !this_thr->th.th_team_bt_set))
4940b57cec5SDimitry Andric       // Force immediate suspend if not set by user and more threads than
4950b57cec5SDimitry Andric       // available procs
4960b57cec5SDimitry Andric       hibernate = 0;
4970b57cec5SDimitry Andric     else
4980b57cec5SDimitry Andric       hibernate = this_thr->th.th_team_bt_intervals;
4990b57cec5SDimitry Andric #else
5000b57cec5SDimitry Andric     hibernate = this_thr->th.th_team_bt_intervals;
5010b57cec5SDimitry Andric #endif /* KMP_ADJUST_BLOCKTIME */
5020b57cec5SDimitry Andric 
5030b57cec5SDimitry Andric     /* If the blocktime is nonzero, we want to make sure that we spin wait for
5040b57cec5SDimitry Andric        the entirety of the specified #intervals, plus up to one interval more.
5050b57cec5SDimitry Andric        This increment make certain that this thread doesn't go to sleep too
5060b57cec5SDimitry Andric        soon.  */
5070b57cec5SDimitry Andric     if (hibernate != 0)
5080b57cec5SDimitry Andric       hibernate++;
5090b57cec5SDimitry Andric 
5100b57cec5SDimitry Andric     // Add in the current time value.
5110b57cec5SDimitry Andric     hibernate += TCR_4(__kmp_global.g.g_time.dt.t_value);
5120b57cec5SDimitry Andric     KF_TRACE(20, ("__kmp_wait_sleep: T#%d now=%d, hibernate=%d, intervals=%d\n",
5130b57cec5SDimitry Andric                   th_gtid, __kmp_global.g.g_time.dt.t_value, hibernate,
5140b57cec5SDimitry Andric                   hibernate - __kmp_global.g.g_time.dt.t_value));
5150b57cec5SDimitry Andric #else
5160b57cec5SDimitry Andric     if (__kmp_pause_status == kmp_soft_paused) {
5170b57cec5SDimitry Andric       // Force immediate suspend
5180b57cec5SDimitry Andric       hibernate_goal = KMP_NOW();
5190b57cec5SDimitry Andric     } else
5200b57cec5SDimitry Andric       hibernate_goal = KMP_NOW() + this_thr->th.th_team_bt_intervals;
5210b57cec5SDimitry Andric     poll_count = 0;
522fe6060f1SDimitry Andric     (void)poll_count;
5230b57cec5SDimitry Andric #endif // KMP_USE_MONITOR
5240b57cec5SDimitry Andric   }
5250b57cec5SDimitry Andric 
5260b57cec5SDimitry Andric   KMP_MB();
5270b57cec5SDimitry Andric 
5280b57cec5SDimitry Andric   // Main wait spin loop
5290b57cec5SDimitry Andric   while (flag->notdone_check()) {
5300b57cec5SDimitry Andric     kmp_task_team_t *task_team = NULL;
5310b57cec5SDimitry Andric     if (__kmp_tasking_mode != tskm_immediate_exec) {
5320b57cec5SDimitry Andric       task_team = this_thr->th.th_task_team;
5330b57cec5SDimitry Andric       /* If the thread's task team pointer is NULL, it means one of 3 things:
5340b57cec5SDimitry Andric          1) A newly-created thread is first being released by
5350b57cec5SDimitry Andric          __kmp_fork_barrier(), and its task team has not been set up yet.
5360b57cec5SDimitry Andric          2) All tasks have been executed to completion.
5370b57cec5SDimitry Andric          3) Tasking is off for this region.  This could be because we are in a
5380b57cec5SDimitry Andric          serialized region (perhaps the outer one), or else tasking was manually
5390b57cec5SDimitry Andric          disabled (KMP_TASKING=0).  */
5400b57cec5SDimitry Andric       if (task_team != NULL) {
5410b57cec5SDimitry Andric         if (TCR_SYNC_4(task_team->tt.tt_active)) {
542349cc55cSDimitry Andric           if (KMP_TASKING_ENABLED(task_team)) {
5430b57cec5SDimitry Andric             flag->execute_tasks(
5440b57cec5SDimitry Andric                 this_thr, th_gtid, final_spin,
5450b57cec5SDimitry Andric                 &tasks_completed USE_ITT_BUILD_ARG(itt_sync_obj), 0);
546349cc55cSDimitry Andric           } else
5470b57cec5SDimitry Andric             this_thr->th.th_reap_state = KMP_SAFE_TO_REAP;
5480b57cec5SDimitry Andric         } else {
5490b57cec5SDimitry Andric           KMP_DEBUG_ASSERT(!KMP_MASTER_TID(this_thr->th.th_info.ds.ds_tid));
5500b57cec5SDimitry Andric #if OMPT_SUPPORT
5510b57cec5SDimitry Andric           // task-team is done now, other cases should be catched above
5520b57cec5SDimitry Andric           if (final_spin && ompt_enabled.enabled)
5530b57cec5SDimitry Andric             __ompt_implicit_task_end(this_thr, ompt_entry_state, tId);
5540b57cec5SDimitry Andric #endif
5550b57cec5SDimitry Andric           this_thr->th.th_task_team = NULL;
5560b57cec5SDimitry Andric           this_thr->th.th_reap_state = KMP_SAFE_TO_REAP;
5570b57cec5SDimitry Andric         }
5580b57cec5SDimitry Andric       } else {
5590b57cec5SDimitry Andric         this_thr->th.th_reap_state = KMP_SAFE_TO_REAP;
5600b57cec5SDimitry Andric       } // if
5610b57cec5SDimitry Andric     } // if
5620b57cec5SDimitry Andric 
5630b57cec5SDimitry Andric     KMP_FSYNC_SPIN_PREPARE(CCAST(void *, spin));
5640b57cec5SDimitry Andric     if (TCR_4(__kmp_global.g.g_done)) {
5650b57cec5SDimitry Andric       if (__kmp_global.g.g_abort)
5660b57cec5SDimitry Andric         __kmp_abort_thread();
5670b57cec5SDimitry Andric       break;
5680b57cec5SDimitry Andric     }
5690b57cec5SDimitry Andric 
5700b57cec5SDimitry Andric     // If we are oversubscribed, or have waited a bit (and
5710b57cec5SDimitry Andric     // KMP_LIBRARY=throughput), then yield
57204eeddc0SDimitry Andric     KMP_YIELD_OVERSUB_ELSE_SPIN(spins, time);
5730b57cec5SDimitry Andric 
5740b57cec5SDimitry Andric #if KMP_STATS_ENABLED
5750b57cec5SDimitry Andric     // Check if thread has been signalled to idle state
5760b57cec5SDimitry Andric     // This indicates that the logical "join-barrier" has finished
5770b57cec5SDimitry Andric     if (this_thr->th.th_stats->isIdle() &&
5780b57cec5SDimitry Andric         KMP_GET_THREAD_STATE() == FORK_JOIN_BARRIER) {
5790b57cec5SDimitry Andric       KMP_SET_THREAD_STATE(IDLE);
5800b57cec5SDimitry Andric       KMP_PUSH_PARTITIONED_TIMER(OMP_idle);
5810b57cec5SDimitry Andric     }
5820b57cec5SDimitry Andric #endif
5830b57cec5SDimitry Andric     // Check if the barrier surrounding this wait loop has been cancelled
584e8d8bef9SDimitry Andric     if (Cancellable) {
5850b57cec5SDimitry Andric       kmp_team_t *team = this_thr->th.th_team;
5860b57cec5SDimitry Andric       if (team && team->t.t_cancel_request == cancel_parallel)
5870b57cec5SDimitry Andric         break;
5880b57cec5SDimitry Andric     }
5890b57cec5SDimitry Andric 
590e8d8bef9SDimitry Andric     // For hidden helper thread, if task_team is nullptr, it means the main
591e8d8bef9SDimitry Andric     // thread has not released the barrier. We cannot wait here because once the
592e8d8bef9SDimitry Andric     // main thread releases all children barriers, all hidden helper threads are
593e8d8bef9SDimitry Andric     // still sleeping. This leads to a problem that following configuration,
594e8d8bef9SDimitry Andric     // such as task team sync, will not be performed such that this thread does
595e8d8bef9SDimitry Andric     // not have task team. Usually it is not bad. However, a corner case is,
596e8d8bef9SDimitry Andric     // when the first task encountered is an untied task, the check in
597e8d8bef9SDimitry Andric     // __kmp_task_alloc will crash because it uses the task team pointer without
598e8d8bef9SDimitry Andric     // checking whether it is nullptr. It is probably under some kind of
599e8d8bef9SDimitry Andric     // assumption.
600e8d8bef9SDimitry Andric     if (task_team && KMP_HIDDEN_HELPER_WORKER_THREAD(th_gtid) &&
601e8d8bef9SDimitry Andric         !TCR_4(__kmp_hidden_helper_team_done)) {
602e8d8bef9SDimitry Andric       // If there is still hidden helper tasks to be executed, the hidden helper
603e8d8bef9SDimitry Andric       // thread will not enter a waiting status.
604e8d8bef9SDimitry Andric       if (KMP_ATOMIC_LD_ACQ(&__kmp_unexecuted_hidden_helper_tasks) == 0) {
605e8d8bef9SDimitry Andric         __kmp_hidden_helper_worker_thread_wait();
606e8d8bef9SDimitry Andric       }
607e8d8bef9SDimitry Andric       continue;
608e8d8bef9SDimitry Andric     }
609e8d8bef9SDimitry Andric 
6100b57cec5SDimitry Andric     // Don't suspend if KMP_BLOCKTIME is set to "infinite"
6110b57cec5SDimitry Andric     if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME &&
6120b57cec5SDimitry Andric         __kmp_pause_status != kmp_soft_paused)
6130b57cec5SDimitry Andric       continue;
6140b57cec5SDimitry Andric 
6150b57cec5SDimitry Andric     // Don't suspend if there is a likelihood of new tasks being spawned.
61681ad6265SDimitry Andric     if (task_team != NULL && TCR_4(task_team->tt.tt_found_tasks) &&
61781ad6265SDimitry Andric         !__kmp_wpolicy_passive)
6180b57cec5SDimitry Andric       continue;
6190b57cec5SDimitry Andric 
6200b57cec5SDimitry Andric #if KMP_USE_MONITOR
6210b57cec5SDimitry Andric     // If we have waited a bit more, fall asleep
6220b57cec5SDimitry Andric     if (TCR_4(__kmp_global.g.g_time.dt.t_value) < hibernate)
6230b57cec5SDimitry Andric       continue;
6240b57cec5SDimitry Andric #else
6250b57cec5SDimitry Andric     if (KMP_BLOCKING(hibernate_goal, poll_count++))
6260b57cec5SDimitry Andric       continue;
6270b57cec5SDimitry Andric #endif
6280b57cec5SDimitry Andric     // Don't suspend if wait loop designated non-sleepable
6290b57cec5SDimitry Andric     // in template parameters
630e8d8bef9SDimitry Andric     if (!Sleepable)
6310b57cec5SDimitry Andric       continue;
6320b57cec5SDimitry Andric 
633e8d8bef9SDimitry Andric #if KMP_HAVE_MWAIT || KMP_HAVE_UMWAIT
634e8d8bef9SDimitry Andric     if (__kmp_mwait_enabled || __kmp_umwait_enabled) {
635e8d8bef9SDimitry Andric       KF_TRACE(50, ("__kmp_wait_sleep: T#%d using monitor/mwait\n", th_gtid));
636e8d8bef9SDimitry Andric       flag->mwait(th_gtid);
637e8d8bef9SDimitry Andric     } else {
638e8d8bef9SDimitry Andric #endif
6390b57cec5SDimitry Andric       KF_TRACE(50, ("__kmp_wait_sleep: T#%d suspend time reached\n", th_gtid));
6400b57cec5SDimitry Andric #if KMP_OS_UNIX
6410b57cec5SDimitry Andric       if (final_spin)
6420b57cec5SDimitry Andric         KMP_ATOMIC_ST_REL(&this_thr->th.th_blocking, false);
6430b57cec5SDimitry Andric #endif
6440b57cec5SDimitry Andric       flag->suspend(th_gtid);
6450b57cec5SDimitry Andric #if KMP_OS_UNIX
6460b57cec5SDimitry Andric       if (final_spin)
6470b57cec5SDimitry Andric         KMP_ATOMIC_ST_REL(&this_thr->th.th_blocking, true);
6480b57cec5SDimitry Andric #endif
649e8d8bef9SDimitry Andric #if KMP_HAVE_MWAIT || KMP_HAVE_UMWAIT
650e8d8bef9SDimitry Andric     }
651e8d8bef9SDimitry Andric #endif
6520b57cec5SDimitry Andric 
6530b57cec5SDimitry Andric     if (TCR_4(__kmp_global.g.g_done)) {
6540b57cec5SDimitry Andric       if (__kmp_global.g.g_abort)
6550b57cec5SDimitry Andric         __kmp_abort_thread();
6560b57cec5SDimitry Andric       break;
6570b57cec5SDimitry Andric     } else if (__kmp_tasking_mode != tskm_immediate_exec &&
6580b57cec5SDimitry Andric                this_thr->th.th_reap_state == KMP_SAFE_TO_REAP) {
6590b57cec5SDimitry Andric       this_thr->th.th_reap_state = KMP_NOT_SAFE_TO_REAP;
6600b57cec5SDimitry Andric     }
6610b57cec5SDimitry Andric     // TODO: If thread is done with work and times out, disband/free
6620b57cec5SDimitry Andric   }
6630b57cec5SDimitry Andric 
6640b57cec5SDimitry Andric #if OMPT_SUPPORT
6650b57cec5SDimitry Andric   ompt_state_t ompt_exit_state = this_thr->th.ompt_thread_info.state;
6660b57cec5SDimitry Andric   if (ompt_enabled.enabled && ompt_exit_state != ompt_state_undefined) {
6670b57cec5SDimitry Andric #if OMPT_OPTIONAL
6680b57cec5SDimitry Andric     if (final_spin) {
6690b57cec5SDimitry Andric       __ompt_implicit_task_end(this_thr, ompt_exit_state, tId);
6700b57cec5SDimitry Andric       ompt_exit_state = this_thr->th.ompt_thread_info.state;
6710b57cec5SDimitry Andric     }
6720b57cec5SDimitry Andric #endif
6730b57cec5SDimitry Andric     if (ompt_exit_state == ompt_state_idle) {
6740b57cec5SDimitry Andric       this_thr->th.ompt_thread_info.state = ompt_state_overhead;
6750b57cec5SDimitry Andric     }
6760b57cec5SDimitry Andric   }
6770b57cec5SDimitry Andric #endif
6780b57cec5SDimitry Andric #if KMP_STATS_ENABLED
6790b57cec5SDimitry Andric   // If we were put into idle state, pop that off the state stack
6800b57cec5SDimitry Andric   if (KMP_GET_THREAD_STATE() == IDLE) {
6810b57cec5SDimitry Andric     KMP_POP_PARTITIONED_TIMER();
6820b57cec5SDimitry Andric     KMP_SET_THREAD_STATE(thread_state);
6830b57cec5SDimitry Andric     this_thr->th.th_stats->resetIdleFlag();
6840b57cec5SDimitry Andric   }
6850b57cec5SDimitry Andric #endif
6860b57cec5SDimitry Andric 
6870b57cec5SDimitry Andric #if KMP_OS_UNIX
6880b57cec5SDimitry Andric   if (final_spin)
6890b57cec5SDimitry Andric     KMP_ATOMIC_ST_REL(&this_thr->th.th_blocking, false);
6900b57cec5SDimitry Andric #endif
6910b57cec5SDimitry Andric   KMP_FSYNC_SPIN_ACQUIRED(CCAST(void *, spin));
692e8d8bef9SDimitry Andric   if (Cancellable) {
6930b57cec5SDimitry Andric     kmp_team_t *team = this_thr->th.th_team;
6940b57cec5SDimitry Andric     if (team && team->t.t_cancel_request == cancel_parallel) {
6950b57cec5SDimitry Andric       if (tasks_completed) {
6960b57cec5SDimitry Andric         // undo the previous decrement of unfinished_threads so that the
6970b57cec5SDimitry Andric         // thread can decrement at the join barrier with no problem
6980b57cec5SDimitry Andric         kmp_task_team_t *task_team = this_thr->th.th_task_team;
6990b57cec5SDimitry Andric         std::atomic<kmp_int32> *unfinished_threads =
7000b57cec5SDimitry Andric             &(task_team->tt.tt_unfinished_threads);
7010b57cec5SDimitry Andric         KMP_ATOMIC_INC(unfinished_threads);
7020b57cec5SDimitry Andric       }
7030b57cec5SDimitry Andric       return true;
7040b57cec5SDimitry Andric     }
7050b57cec5SDimitry Andric   }
7060b57cec5SDimitry Andric   return false;
7070b57cec5SDimitry Andric }
7080b57cec5SDimitry Andric 
709e8d8bef9SDimitry Andric #if KMP_HAVE_MWAIT || KMP_HAVE_UMWAIT
710e8d8bef9SDimitry Andric // Set up a monitor on the flag variable causing the calling thread to wait in
711e8d8bef9SDimitry Andric // a less active state until the flag variable is modified.
712e8d8bef9SDimitry Andric template <class C>
713e8d8bef9SDimitry Andric static inline void __kmp_mwait_template(int th_gtid, C *flag) {
714e8d8bef9SDimitry Andric   KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(USER_mwait);
715e8d8bef9SDimitry Andric   kmp_info_t *th = __kmp_threads[th_gtid];
716e8d8bef9SDimitry Andric 
717e8d8bef9SDimitry Andric   KF_TRACE(30, ("__kmp_mwait_template: T#%d enter for flag = %p\n", th_gtid,
718e8d8bef9SDimitry Andric                 flag->get()));
719e8d8bef9SDimitry Andric 
720e8d8bef9SDimitry Andric   // User-level mwait is available
721e8d8bef9SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_mwait_enabled || __kmp_umwait_enabled);
722e8d8bef9SDimitry Andric 
723e8d8bef9SDimitry Andric   __kmp_suspend_initialize_thread(th);
724e8d8bef9SDimitry Andric   __kmp_lock_suspend_mx(th);
725e8d8bef9SDimitry Andric 
726e8d8bef9SDimitry Andric   volatile void *spin = flag->get();
727e8d8bef9SDimitry Andric   void *cacheline = (void *)(kmp_uintptr_t(spin) & ~(CACHE_LINE - 1));
728e8d8bef9SDimitry Andric 
729e8d8bef9SDimitry Andric   if (!flag->done_check()) {
730e8d8bef9SDimitry Andric     // Mark thread as no longer active
731e8d8bef9SDimitry Andric     th->th.th_active = FALSE;
732e8d8bef9SDimitry Andric     if (th->th.th_active_in_pool) {
733e8d8bef9SDimitry Andric       th->th.th_active_in_pool = FALSE;
734e8d8bef9SDimitry Andric       KMP_ATOMIC_DEC(&__kmp_thread_pool_active_nth);
735e8d8bef9SDimitry Andric       KMP_DEBUG_ASSERT(TCR_4(__kmp_thread_pool_active_nth) >= 0);
736e8d8bef9SDimitry Andric     }
737e8d8bef9SDimitry Andric     flag->set_sleeping();
738e8d8bef9SDimitry Andric     KF_TRACE(50, ("__kmp_mwait_template: T#%d calling monitor\n", th_gtid));
739e8d8bef9SDimitry Andric #if KMP_HAVE_UMWAIT
740e8d8bef9SDimitry Andric     if (__kmp_umwait_enabled) {
741e8d8bef9SDimitry Andric       __kmp_umonitor(cacheline);
742e8d8bef9SDimitry Andric     }
743e8d8bef9SDimitry Andric #elif KMP_HAVE_MWAIT
744e8d8bef9SDimitry Andric     if (__kmp_mwait_enabled) {
745e8d8bef9SDimitry Andric       __kmp_mm_monitor(cacheline, 0, 0);
746e8d8bef9SDimitry Andric     }
747e8d8bef9SDimitry Andric #endif
748e8d8bef9SDimitry Andric     // To avoid a race, check flag between 'monitor' and 'mwait'. A write to
749e8d8bef9SDimitry Andric     // the address could happen after the last time we checked and before
750e8d8bef9SDimitry Andric     // monitoring started, in which case monitor can't detect the change.
751e8d8bef9SDimitry Andric     if (flag->done_check())
752e8d8bef9SDimitry Andric       flag->unset_sleeping();
753e8d8bef9SDimitry Andric     else {
754e8d8bef9SDimitry Andric       // if flag changes here, wake-up happens immediately
755e8d8bef9SDimitry Andric       TCW_PTR(th->th.th_sleep_loc, (void *)flag);
756349cc55cSDimitry Andric       th->th.th_sleep_loc_type = flag->get_type();
757e8d8bef9SDimitry Andric       __kmp_unlock_suspend_mx(th);
758e8d8bef9SDimitry Andric       KF_TRACE(50, ("__kmp_mwait_template: T#%d calling mwait\n", th_gtid));
759e8d8bef9SDimitry Andric #if KMP_HAVE_UMWAIT
760e8d8bef9SDimitry Andric       if (__kmp_umwait_enabled) {
761e8d8bef9SDimitry Andric         __kmp_umwait(1, 100); // to do: enable ctrl via hints, backoff counter
762e8d8bef9SDimitry Andric       }
763e8d8bef9SDimitry Andric #elif KMP_HAVE_MWAIT
764e8d8bef9SDimitry Andric       if (__kmp_mwait_enabled) {
765e8d8bef9SDimitry Andric         __kmp_mm_mwait(0, __kmp_mwait_hints);
766e8d8bef9SDimitry Andric       }
767e8d8bef9SDimitry Andric #endif
768e8d8bef9SDimitry Andric       KF_TRACE(50, ("__kmp_mwait_template: T#%d mwait done\n", th_gtid));
769e8d8bef9SDimitry Andric       __kmp_lock_suspend_mx(th);
770e8d8bef9SDimitry Andric       // Clean up sleep info; doesn't matter how/why this thread stopped waiting
771e8d8bef9SDimitry Andric       if (flag->is_sleeping())
772e8d8bef9SDimitry Andric         flag->unset_sleeping();
773e8d8bef9SDimitry Andric       TCW_PTR(th->th.th_sleep_loc, NULL);
774349cc55cSDimitry Andric       th->th.th_sleep_loc_type = flag_unset;
775e8d8bef9SDimitry Andric     }
776e8d8bef9SDimitry Andric     // Mark thread as active again
777e8d8bef9SDimitry Andric     th->th.th_active = TRUE;
778e8d8bef9SDimitry Andric     if (TCR_4(th->th.th_in_pool)) {
779e8d8bef9SDimitry Andric       KMP_ATOMIC_INC(&__kmp_thread_pool_active_nth);
780e8d8bef9SDimitry Andric       th->th.th_active_in_pool = TRUE;
781e8d8bef9SDimitry Andric     }
782e8d8bef9SDimitry Andric   } // Drop out to main wait loop to check flag, handle tasks, etc.
783e8d8bef9SDimitry Andric   __kmp_unlock_suspend_mx(th);
784e8d8bef9SDimitry Andric   KF_TRACE(30, ("__kmp_mwait_template: T#%d exit\n", th_gtid));
785e8d8bef9SDimitry Andric }
786e8d8bef9SDimitry Andric #endif // KMP_HAVE_MWAIT || KMP_HAVE_UMWAIT
787e8d8bef9SDimitry Andric 
7880b57cec5SDimitry Andric /* Release any threads specified as waiting on the flag by releasing the flag
7890b57cec5SDimitry Andric    and resume the waiting thread if indicated by the sleep bit(s). A thread that
7900b57cec5SDimitry Andric    calls __kmp_wait_template must call this function to wake up the potentially
7910b57cec5SDimitry Andric    sleeping thread and prevent deadlocks!  */
7920b57cec5SDimitry Andric template <class C> static inline void __kmp_release_template(C *flag) {
7930b57cec5SDimitry Andric #ifdef KMP_DEBUG
7940b57cec5SDimitry Andric   int gtid = TCR_4(__kmp_init_gtid) ? __kmp_get_gtid() : -1;
7950b57cec5SDimitry Andric #endif
7960b57cec5SDimitry Andric   KF_TRACE(20, ("__kmp_release: T#%d releasing flag(%x)\n", gtid, flag->get()));
7970b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(flag->get());
7980b57cec5SDimitry Andric   KMP_FSYNC_RELEASING(flag->get_void_p());
7990b57cec5SDimitry Andric 
8000b57cec5SDimitry Andric   flag->internal_release();
8010b57cec5SDimitry Andric 
8020b57cec5SDimitry Andric   KF_TRACE(100, ("__kmp_release: T#%d set new spin=%d\n", gtid, flag->get(),
8030b57cec5SDimitry Andric                  flag->load()));
8040b57cec5SDimitry Andric 
8050b57cec5SDimitry Andric   if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
8060b57cec5SDimitry Andric     // Only need to check sleep stuff if infinite block time not set.
8070b57cec5SDimitry Andric     // Are *any* threads waiting on flag sleeping?
8080b57cec5SDimitry Andric     if (flag->is_any_sleeping()) {
8090b57cec5SDimitry Andric       for (unsigned int i = 0; i < flag->get_num_waiters(); ++i) {
8100b57cec5SDimitry Andric         // if sleeping waiter exists at i, sets current_waiter to i inside flag
8110b57cec5SDimitry Andric         kmp_info_t *waiter = flag->get_waiter(i);
8120b57cec5SDimitry Andric         if (waiter) {
8130b57cec5SDimitry Andric           int wait_gtid = waiter->th.th_info.ds.ds_gtid;
8140b57cec5SDimitry Andric           // Wake up thread if needed
8150b57cec5SDimitry Andric           KF_TRACE(50, ("__kmp_release: T#%d waking up thread T#%d since sleep "
8160b57cec5SDimitry Andric                         "flag(%p) set\n",
8170b57cec5SDimitry Andric                         gtid, wait_gtid, flag->get()));
8180b57cec5SDimitry Andric           flag->resume(wait_gtid); // unsets flag's current_waiter when done
8190b57cec5SDimitry Andric         }
8200b57cec5SDimitry Andric       }
8210b57cec5SDimitry Andric     }
8220b57cec5SDimitry Andric   }
8230b57cec5SDimitry Andric }
8240b57cec5SDimitry Andric 
825e8d8bef9SDimitry Andric template <bool Cancellable, bool Sleepable>
826349cc55cSDimitry Andric class kmp_flag_32 : public kmp_flag_atomic<kmp_uint32, flag32, Sleepable> {
8270b57cec5SDimitry Andric public:
828e8d8bef9SDimitry Andric   kmp_flag_32(std::atomic<kmp_uint32> *p)
829349cc55cSDimitry Andric       : kmp_flag_atomic<kmp_uint32, flag32, Sleepable>(p) {}
8300b57cec5SDimitry Andric   kmp_flag_32(std::atomic<kmp_uint32> *p, kmp_info_t *thr)
831349cc55cSDimitry Andric       : kmp_flag_atomic<kmp_uint32, flag32, Sleepable>(p, thr) {}
8320b57cec5SDimitry Andric   kmp_flag_32(std::atomic<kmp_uint32> *p, kmp_uint32 c)
833349cc55cSDimitry Andric       : kmp_flag_atomic<kmp_uint32, flag32, Sleepable>(p, c) {}
8340b57cec5SDimitry Andric   void suspend(int th_gtid) { __kmp_suspend_32(th_gtid, this); }
835e8d8bef9SDimitry Andric #if KMP_HAVE_MWAIT || KMP_HAVE_UMWAIT
836e8d8bef9SDimitry Andric   void mwait(int th_gtid) { __kmp_mwait_32(th_gtid, this); }
837e8d8bef9SDimitry Andric #endif
8380b57cec5SDimitry Andric   void resume(int th_gtid) { __kmp_resume_32(th_gtid, this); }
8390b57cec5SDimitry Andric   int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin,
8400b57cec5SDimitry Andric                     int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
8410b57cec5SDimitry Andric                     kmp_int32 is_constrained) {
8420b57cec5SDimitry Andric     return __kmp_execute_tasks_32(
8430b57cec5SDimitry Andric         this_thr, gtid, this, final_spin,
8440b57cec5SDimitry Andric         thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
8450b57cec5SDimitry Andric   }
846e8d8bef9SDimitry Andric   bool wait(kmp_info_t *this_thr,
8470b57cec5SDimitry Andric             int final_spin USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
8480b57cec5SDimitry Andric     if (final_spin)
849e8d8bef9SDimitry Andric       return __kmp_wait_template<kmp_flag_32, TRUE, Cancellable, Sleepable>(
8500b57cec5SDimitry Andric           this_thr, this USE_ITT_BUILD_ARG(itt_sync_obj));
8510b57cec5SDimitry Andric     else
852e8d8bef9SDimitry Andric       return __kmp_wait_template<kmp_flag_32, FALSE, Cancellable, Sleepable>(
8530b57cec5SDimitry Andric           this_thr, this USE_ITT_BUILD_ARG(itt_sync_obj));
8540b57cec5SDimitry Andric   }
8550b57cec5SDimitry Andric   void release() { __kmp_release_template(this); }
8560b57cec5SDimitry Andric   flag_type get_ptr_type() { return flag32; }
8570b57cec5SDimitry Andric };
8580b57cec5SDimitry Andric 
859e8d8bef9SDimitry Andric template <bool Cancellable, bool Sleepable>
860349cc55cSDimitry Andric class kmp_flag_64 : public kmp_flag_native<kmp_uint64, flag64, Sleepable> {
8610b57cec5SDimitry Andric public:
862e8d8bef9SDimitry Andric   kmp_flag_64(volatile kmp_uint64 *p)
863349cc55cSDimitry Andric       : kmp_flag_native<kmp_uint64, flag64, Sleepable>(p) {}
8640b57cec5SDimitry Andric   kmp_flag_64(volatile kmp_uint64 *p, kmp_info_t *thr)
865349cc55cSDimitry Andric       : kmp_flag_native<kmp_uint64, flag64, Sleepable>(p, thr) {}
8660b57cec5SDimitry Andric   kmp_flag_64(volatile kmp_uint64 *p, kmp_uint64 c)
867349cc55cSDimitry Andric       : kmp_flag_native<kmp_uint64, flag64, Sleepable>(p, c) {}
868349cc55cSDimitry Andric   kmp_flag_64(volatile kmp_uint64 *p, kmp_uint64 c, std::atomic<bool> *loc)
869349cc55cSDimitry Andric       : kmp_flag_native<kmp_uint64, flag64, Sleepable>(p, c, loc) {}
8700b57cec5SDimitry Andric   void suspend(int th_gtid) { __kmp_suspend_64(th_gtid, this); }
871e8d8bef9SDimitry Andric #if KMP_HAVE_MWAIT || KMP_HAVE_UMWAIT
872e8d8bef9SDimitry Andric   void mwait(int th_gtid) { __kmp_mwait_64(th_gtid, this); }
873e8d8bef9SDimitry Andric #endif
8740b57cec5SDimitry Andric   void resume(int th_gtid) { __kmp_resume_64(th_gtid, this); }
8750b57cec5SDimitry Andric   int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin,
8760b57cec5SDimitry Andric                     int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
8770b57cec5SDimitry Andric                     kmp_int32 is_constrained) {
8780b57cec5SDimitry Andric     return __kmp_execute_tasks_64(
8790b57cec5SDimitry Andric         this_thr, gtid, this, final_spin,
8800b57cec5SDimitry Andric         thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
8810b57cec5SDimitry Andric   }
882e8d8bef9SDimitry Andric   bool wait(kmp_info_t *this_thr,
8830b57cec5SDimitry Andric             int final_spin USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
8840b57cec5SDimitry Andric     if (final_spin)
885e8d8bef9SDimitry Andric       return __kmp_wait_template<kmp_flag_64, TRUE, Cancellable, Sleepable>(
8860b57cec5SDimitry Andric           this_thr, this USE_ITT_BUILD_ARG(itt_sync_obj));
8870b57cec5SDimitry Andric     else
888e8d8bef9SDimitry Andric       return __kmp_wait_template<kmp_flag_64, FALSE, Cancellable, Sleepable>(
8890b57cec5SDimitry Andric           this_thr, this USE_ITT_BUILD_ARG(itt_sync_obj));
8900b57cec5SDimitry Andric   }
8910b57cec5SDimitry Andric   void release() { __kmp_release_template(this); }
8920b57cec5SDimitry Andric   flag_type get_ptr_type() { return flag64; }
8930b57cec5SDimitry Andric };
8940b57cec5SDimitry Andric 
895349cc55cSDimitry Andric template <bool Cancellable, bool Sleepable>
896349cc55cSDimitry Andric class kmp_atomic_flag_64
897349cc55cSDimitry Andric     : public kmp_flag_atomic<kmp_uint64, atomic_flag64, Sleepable> {
898349cc55cSDimitry Andric public:
899349cc55cSDimitry Andric   kmp_atomic_flag_64(std::atomic<kmp_uint64> *p)
900349cc55cSDimitry Andric       : kmp_flag_atomic<kmp_uint64, atomic_flag64, Sleepable>(p) {}
901349cc55cSDimitry Andric   kmp_atomic_flag_64(std::atomic<kmp_uint64> *p, kmp_info_t *thr)
902349cc55cSDimitry Andric       : kmp_flag_atomic<kmp_uint64, atomic_flag64, Sleepable>(p, thr) {}
903349cc55cSDimitry Andric   kmp_atomic_flag_64(std::atomic<kmp_uint64> *p, kmp_uint64 c)
904349cc55cSDimitry Andric       : kmp_flag_atomic<kmp_uint64, atomic_flag64, Sleepable>(p, c) {}
905349cc55cSDimitry Andric   kmp_atomic_flag_64(std::atomic<kmp_uint64> *p, kmp_uint64 c,
906349cc55cSDimitry Andric                      std::atomic<bool> *loc)
907349cc55cSDimitry Andric       : kmp_flag_atomic<kmp_uint64, atomic_flag64, Sleepable>(p, c, loc) {}
908349cc55cSDimitry Andric   void suspend(int th_gtid) { __kmp_atomic_suspend_64(th_gtid, this); }
909349cc55cSDimitry Andric   void mwait(int th_gtid) { __kmp_atomic_mwait_64(th_gtid, this); }
910349cc55cSDimitry Andric   void resume(int th_gtid) { __kmp_atomic_resume_64(th_gtid, this); }
911349cc55cSDimitry Andric   int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin,
912349cc55cSDimitry Andric                     int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
913349cc55cSDimitry Andric                     kmp_int32 is_constrained) {
914349cc55cSDimitry Andric     return __kmp_atomic_execute_tasks_64(
915349cc55cSDimitry Andric         this_thr, gtid, this, final_spin,
916349cc55cSDimitry Andric         thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
917349cc55cSDimitry Andric   }
918349cc55cSDimitry Andric   bool wait(kmp_info_t *this_thr,
919349cc55cSDimitry Andric             int final_spin USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
920349cc55cSDimitry Andric     if (final_spin)
921349cc55cSDimitry Andric       return __kmp_wait_template<kmp_atomic_flag_64, TRUE, Cancellable,
922349cc55cSDimitry Andric                                  Sleepable>(
923349cc55cSDimitry Andric           this_thr, this USE_ITT_BUILD_ARG(itt_sync_obj));
924349cc55cSDimitry Andric     else
925349cc55cSDimitry Andric       return __kmp_wait_template<kmp_atomic_flag_64, FALSE, Cancellable,
926349cc55cSDimitry Andric                                  Sleepable>(
927349cc55cSDimitry Andric           this_thr, this USE_ITT_BUILD_ARG(itt_sync_obj));
928349cc55cSDimitry Andric   }
929349cc55cSDimitry Andric   void release() { __kmp_release_template(this); }
930349cc55cSDimitry Andric   flag_type get_ptr_type() { return atomic_flag64; }
931349cc55cSDimitry Andric };
932349cc55cSDimitry Andric 
9330b57cec5SDimitry Andric // Hierarchical 64-bit on-core barrier instantiation
934349cc55cSDimitry Andric class kmp_flag_oncore : public kmp_flag_native<kmp_uint64, flag_oncore, false> {
935349cc55cSDimitry Andric   kmp_uint32 offset; /**< Portion of flag of interest for an operation. */
9360b57cec5SDimitry Andric   bool flag_switch; /**< Indicates a switch in flag location. */
9370b57cec5SDimitry Andric   enum barrier_type bt; /**< Barrier type. */
938349cc55cSDimitry Andric   kmp_info_t *this_thr; /**< Thread to redirect to different flag location. */
9390b57cec5SDimitry Andric #if USE_ITT_BUILD
940349cc55cSDimitry Andric   void *itt_sync_obj; /**< ITT object to pass to new flag location. */
9410b57cec5SDimitry Andric #endif
9420b57cec5SDimitry Andric   unsigned char &byteref(volatile kmp_uint64 *loc, size_t offset) {
9430b57cec5SDimitry Andric     return (RCAST(unsigned char *, CCAST(kmp_uint64 *, loc)))[offset];
9440b57cec5SDimitry Andric   }
9450b57cec5SDimitry Andric 
9460b57cec5SDimitry Andric public:
9470b57cec5SDimitry Andric   kmp_flag_oncore(volatile kmp_uint64 *p)
948349cc55cSDimitry Andric       : kmp_flag_native<kmp_uint64, flag_oncore, false>(p), flag_switch(false) {
949349cc55cSDimitry Andric   }
9500b57cec5SDimitry Andric   kmp_flag_oncore(volatile kmp_uint64 *p, kmp_uint32 idx)
951349cc55cSDimitry Andric       : kmp_flag_native<kmp_uint64, flag_oncore, false>(p), offset(idx),
952349cc55cSDimitry Andric         flag_switch(false),
953349cc55cSDimitry Andric         bt(bs_last_barrier) USE_ITT_BUILD_ARG(itt_sync_obj(nullptr)) {}
9540b57cec5SDimitry Andric   kmp_flag_oncore(volatile kmp_uint64 *p, kmp_uint64 c, kmp_uint32 idx,
9550b57cec5SDimitry Andric                   enum barrier_type bar_t,
9560b57cec5SDimitry Andric                   kmp_info_t *thr USE_ITT_BUILD_ARG(void *itt))
957349cc55cSDimitry Andric       : kmp_flag_native<kmp_uint64, flag_oncore, false>(p, c), offset(idx),
958349cc55cSDimitry Andric         flag_switch(false), bt(bar_t),
9590b57cec5SDimitry Andric         this_thr(thr) USE_ITT_BUILD_ARG(itt_sync_obj(itt)) {}
960349cc55cSDimitry Andric   virtual ~kmp_flag_oncore() override {}
961349cc55cSDimitry Andric   void *operator new(size_t size) { return __kmp_allocate(size); }
962349cc55cSDimitry Andric   void operator delete(void *p) { __kmp_free(p); }
963349cc55cSDimitry Andric   bool done_check_val(kmp_uint64 old_loc) override {
9640b57cec5SDimitry Andric     return byteref(&old_loc, offset) == checker;
9650b57cec5SDimitry Andric   }
966349cc55cSDimitry Andric   bool done_check() override { return done_check_val(*get()); }
967349cc55cSDimitry Andric   bool notdone_check() override {
9680b57cec5SDimitry Andric     // Calculate flag_switch
9690b57cec5SDimitry Andric     if (this_thr->th.th_bar[bt].bb.wait_flag == KMP_BARRIER_SWITCH_TO_OWN_FLAG)
9700b57cec5SDimitry Andric       flag_switch = true;
9710b57cec5SDimitry Andric     if (byteref(get(), offset) != 1 && !flag_switch)
9720b57cec5SDimitry Andric       return true;
9730b57cec5SDimitry Andric     else if (flag_switch) {
9740b57cec5SDimitry Andric       this_thr->th.th_bar[bt].bb.wait_flag = KMP_BARRIER_SWITCHING;
975e8d8bef9SDimitry Andric       kmp_flag_64<> flag(&this_thr->th.th_bar[bt].bb.b_go,
9760b57cec5SDimitry Andric                          (kmp_uint64)KMP_BARRIER_STATE_BUMP);
9770b57cec5SDimitry Andric       __kmp_wait_64(this_thr, &flag, TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
9780b57cec5SDimitry Andric     }
9790b57cec5SDimitry Andric     return false;
9800b57cec5SDimitry Andric   }
9810b57cec5SDimitry Andric   void internal_release() {
9820b57cec5SDimitry Andric     // Other threads can write their own bytes simultaneously.
9830b57cec5SDimitry Andric     if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME) {
9840b57cec5SDimitry Andric       byteref(get(), offset) = 1;
9850b57cec5SDimitry Andric     } else {
9860b57cec5SDimitry Andric       kmp_uint64 mask = 0;
9870b57cec5SDimitry Andric       byteref(&mask, offset) = 1;
9880b57cec5SDimitry Andric       KMP_TEST_THEN_OR64(get(), mask);
9890b57cec5SDimitry Andric     }
9900b57cec5SDimitry Andric   }
9910b57cec5SDimitry Andric   void wait(kmp_info_t *this_thr, int final_spin) {
9920b57cec5SDimitry Andric     if (final_spin)
9930b57cec5SDimitry Andric       __kmp_wait_template<kmp_flag_oncore, TRUE>(
9940b57cec5SDimitry Andric           this_thr, this USE_ITT_BUILD_ARG(itt_sync_obj));
9950b57cec5SDimitry Andric     else
9960b57cec5SDimitry Andric       __kmp_wait_template<kmp_flag_oncore, FALSE>(
9970b57cec5SDimitry Andric           this_thr, this USE_ITT_BUILD_ARG(itt_sync_obj));
9980b57cec5SDimitry Andric   }
9990b57cec5SDimitry Andric   void release() { __kmp_release_template(this); }
10000b57cec5SDimitry Andric   void suspend(int th_gtid) { __kmp_suspend_oncore(th_gtid, this); }
1001e8d8bef9SDimitry Andric #if KMP_HAVE_MWAIT || KMP_HAVE_UMWAIT
1002e8d8bef9SDimitry Andric   void mwait(int th_gtid) { __kmp_mwait_oncore(th_gtid, this); }
1003e8d8bef9SDimitry Andric #endif
10040b57cec5SDimitry Andric   void resume(int th_gtid) { __kmp_resume_oncore(th_gtid, this); }
10050b57cec5SDimitry Andric   int execute_tasks(kmp_info_t *this_thr, kmp_int32 gtid, int final_spin,
10060b57cec5SDimitry Andric                     int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
10070b57cec5SDimitry Andric                     kmp_int32 is_constrained) {
1008fe6060f1SDimitry Andric #if OMPD_SUPPORT
1009fe6060f1SDimitry Andric     int ret = __kmp_execute_tasks_oncore(
1010fe6060f1SDimitry Andric         this_thr, gtid, this, final_spin,
1011fe6060f1SDimitry Andric         thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
1012fe6060f1SDimitry Andric     if (ompd_state & OMPD_ENABLE_BP)
1013fe6060f1SDimitry Andric       ompd_bp_task_end();
1014fe6060f1SDimitry Andric     return ret;
1015fe6060f1SDimitry Andric #else
10160b57cec5SDimitry Andric     return __kmp_execute_tasks_oncore(
10170b57cec5SDimitry Andric         this_thr, gtid, this, final_spin,
10180b57cec5SDimitry Andric         thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
1019fe6060f1SDimitry Andric #endif
10200b57cec5SDimitry Andric   }
10210b57cec5SDimitry Andric   enum barrier_type get_bt() { return bt; }
10220b57cec5SDimitry Andric   flag_type get_ptr_type() { return flag_oncore; }
10230b57cec5SDimitry Andric };
10240b57cec5SDimitry Andric 
1025349cc55cSDimitry Andric static inline void __kmp_null_resume_wrapper(kmp_info_t *thr) {
1026349cc55cSDimitry Andric   int gtid = __kmp_gtid_from_thread(thr);
1027349cc55cSDimitry Andric   void *flag = CCAST(void *, thr->th.th_sleep_loc);
1028349cc55cSDimitry Andric   flag_type type = thr->th.th_sleep_loc_type;
10290b57cec5SDimitry Andric   if (!flag)
10300b57cec5SDimitry Andric     return;
1031349cc55cSDimitry Andric   // Attempt to wake up a thread: examine its type and call appropriate template
1032349cc55cSDimitry Andric   switch (type) {
10330b57cec5SDimitry Andric   case flag32:
1034349cc55cSDimitry Andric     __kmp_resume_32(gtid, RCAST(kmp_flag_32<> *, flag));
10350b57cec5SDimitry Andric     break;
10360b57cec5SDimitry Andric   case flag64:
1037349cc55cSDimitry Andric     __kmp_resume_64(gtid, RCAST(kmp_flag_64<> *, flag));
1038349cc55cSDimitry Andric     break;
1039349cc55cSDimitry Andric   case atomic_flag64:
1040349cc55cSDimitry Andric     __kmp_atomic_resume_64(gtid, RCAST(kmp_atomic_flag_64<> *, flag));
10410b57cec5SDimitry Andric     break;
10420b57cec5SDimitry Andric   case flag_oncore:
1043349cc55cSDimitry Andric     __kmp_resume_oncore(gtid, RCAST(kmp_flag_oncore *, flag));
10440b57cec5SDimitry Andric     break;
1045349cc55cSDimitry Andric   case flag_unset:
1046349cc55cSDimitry Andric     KF_TRACE(100, ("__kmp_null_resume_wrapper: flag type %d is unset\n", type));
1047349cc55cSDimitry Andric     break;
10480b57cec5SDimitry Andric   }
10490b57cec5SDimitry Andric }
10500b57cec5SDimitry Andric 
10510b57cec5SDimitry Andric /*!
10520b57cec5SDimitry Andric @}
10530b57cec5SDimitry Andric */
10540b57cec5SDimitry Andric 
10550b57cec5SDimitry Andric #endif // KMP_WAIT_RELEASE_H
1056