/// This is a function which gets called periodically by the thread /// manager to allow for maintenance tasks to be executed in the /// scheduler. Returns true if the OS thread calling this function /// has to be terminated (i.e. no more work has to be done). virtual bool wait_or_add_new(std::size_t num_thread, bool running, std::int64_t& idle_loop_count) { std::size_t queues_size = this->queues_.size(); HPX_ASSERT(num_thread < queues_size); std::size_t added = 0; bool result = true; result = this->queues_[num_thread]->wait_or_add_new(running, idle_loop_count, added) && result; if (0 != added) return result; #ifdef HPX_HAVE_THREAD_MINIMAL_DEADLOCK_DETECTION // no new work is available, are we deadlocked? if (HPX_UNLIKELY(minimal_deadlock_detection && LHPX_ENABLED(error))) { bool suspended_only = true; for (std::size_t i = 0; suspended_only && i != queues_size; ++i) { suspended_only = this->queues_[i]->dump_suspended_threads( i, idle_loop_count, running); } if (HPX_UNLIKELY(suspended_only)) { if (running) { LTM_(error) //-V128 << "queue(" << num_thread << "): " << "no new work available, are we deadlocked?"; } else { LHPX_CONSOLE_(hpx::util::logging::level::error) //-V128 << " [TM] queue(" << num_thread << "): " << "no new work available, are we deadlocked?\n"; } } } #endif return result; }
bool dump_suspended_threads(std::size_t num_thread, Map& tm, boost::int64_t& idle_loop_count, bool running) { #ifndef HPX_THREAD_MINIMAL_DEADLOCK_DETECTION HPX_UNUSED(tm); HPX_UNUSED(idle_loop_count); HPX_UNUSED(running); //-V601 return false; #else if (!minimal_deadlock_detection) return false; if (HPX_LIKELY(idle_loop_count++ < HPX_IDLE_LOOP_COUNT_MAX)) return false; // reset idle loop count idle_loop_count = 0; bool result = false; bool collect_suspended = true; bool logged_headline = false; typename Map::const_iterator end = tm.end(); for (typename Map::const_iterator it = tm.begin(); it != end; ++it) { threads::thread_data const* thrd = (*it).get(); threads::thread_state state = thrd->get_state(); threads::thread_state marked_state = thrd->get_marked_state(); if (state != marked_state) { // log each thread only once if (!logged_headline) { if (running) { LTM_(error) //-V128 << "Listing suspended threads while queue (" << num_thread << ") is empty:"; } else { LHPX_CONSOLE_(hpx::util::logging::level::error) //-V128 << " [TM] Listing suspended threads while queue (" << num_thread << ") is empty:\n"; } logged_headline = true; } if (running) { LTM_(error) << "queue(" << num_thread << "): " //-V128 << get_thread_state_name(state) << "(" << std::hex << std::setw(8) << std::setfill('0') << (*it).get() << "." << std::hex << std::setw(2) << std::setfill('0') << thrd->get_thread_phase() << "/" << std::hex << std::setw(8) << std::setfill('0') << thrd->get_component_id() << ")" #ifdef HPX_HAVE_THREAD_PARENT_REFERENCE << " P" << std::hex << std::setw(8) << std::setfill('0') << thrd->get_parent_thread_id() #endif << ": " << thrd->get_description() << ": " << thrd->get_lco_description(); } else { LHPX_CONSOLE_(hpx::util::logging::level::error) << " [TM] " //-V128 << "queue(" << num_thread << "): " << get_thread_state_name(state) << "(" << std::hex << std::setw(8) << std::setfill('0') << (*it).get() << "." << std::hex << std::setw(2) << std::setfill('0') << thrd->get_thread_phase() << "/" << std::hex << std::setw(8) << std::setfill('0') << thrd->get_component_id() << ")" #ifdef HPX_HAVE_THREAD_PARENT_REFERENCE << " P" << std::hex << std::setw(8) << std::setfill('0') << thrd->get_parent_thread_id() #endif << ": " << thrd->get_description() << ": " << thrd->get_lco_description() << "\n"; } thrd->set_marked_state(state); // result should be true if we found only suspended threads if (collect_suspended) { switch(state.get_state()) { case threads::suspended: result = true; // at least one is suspended break; case threads::pending: case threads::active: result = false; // one is active, no deadlock (yet) collect_suspended = false; break; default: // If the thread is terminated we don't care too much // anymore. break; } } } } return result; #endif }
/// This is a function which gets called periodically by the thread /// manager to allow for maintenance tasks to be executed in the /// scheduler. Returns true if the OS thread calling this function /// has to be terminated (i.e. no more work has to be done). virtual bool wait_or_add_new(std::size_t num_thread, bool running, std::int64_t& idle_loop_count) { std::size_t added = 0; bool result = true; std::size_t high_priority_queues = high_priority_queues_.size(); thread_queue_type* this_high_priority_queue = nullptr; thread_queue_type* this_queue = queues_[num_thread]; if (num_thread < high_priority_queues) { this_high_priority_queue = high_priority_queues_[num_thread]; result = this_high_priority_queue->wait_or_add_new(running, idle_loop_count, added) && result; if (0 != added) return result; } result = this_queue->wait_or_add_new( running, idle_loop_count, added) && result; if (0 != added) return result; for (std::size_t idx: victim_threads_[num_thread]) { HPX_ASSERT(idx != num_thread); if (idx < high_priority_queues && num_thread < high_priority_queues) { thread_queue_type* q = high_priority_queues_[idx]; result = this_high_priority_queue-> wait_or_add_new(running, idle_loop_count, added, q) && result; if (0 != added) { q->increment_num_stolen_from_staged(added); this_high_priority_queue-> increment_num_stolen_to_staged(added); return result; } } result = this_queue->wait_or_add_new(running, idle_loop_count, added, queues_[idx]) && result; if (0 != added) { queues_[idx]->increment_num_stolen_from_staged(added); this_queue->increment_num_stolen_to_staged(added); return result; } } #ifdef HPX_HAVE_THREAD_MINIMAL_DEADLOCK_DETECTION // no new work is available, are we deadlocked? if (HPX_UNLIKELY(minimal_deadlock_detection && LHPX_ENABLED(error))) { bool suspended_only = true; for (std::size_t i = 0; suspended_only && i != queues_.size(); ++i) { suspended_only = queues_[i]->dump_suspended_threads( i, idle_loop_count, running); } if (HPX_UNLIKELY(suspended_only)) { if (running) { LTM_(error) //-V128 << "queue(" << num_thread << "): " << "no new work available, are we deadlocked?"; } else { LHPX_CONSOLE_(hpx::util::logging::level::error) //-V128 << " [TM] " //-V128 << "queue(" << num_thread << "): " << "no new work available, are we deadlocked?\n"; } } } #endif result = low_priority_queue_.wait_or_add_new(running, idle_loop_count, added) && result; if (0 != added) return result; return result; }