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