void log_non_empty_queue(char const* const desc, queue_type& queue) { mutex_type::scoped_lock l(mtx_); while (!queue.empty()) { threads::thread_id_type id = queue.front().id_; queue.front().id_ = 0; queue.pop_front(); // we know that the id is actually the pointer to the thread threads::thread_data* thrd = reinterpret_cast<threads::thread_data*>(id); LERR_(info) << "~full_empty_entry: aborting pending thread in " << desc << ": " << get_thread_state_name(thrd->get_state()) << "(" << id << "): " << thrd->get_description(); // forcefully abort thread, do not throw error_code ec(lightweight); threads::set_thread_state(id, threads::pending, threads::wait_abort, threads::thread_priority_normal, ec); if (ec) { LERR_(error) << "~full_empty_entry: could not abort thread" << get_thread_state_name(thrd->get_state()) << "(" << id << "): " << thrd->get_description(); } } }
mutex::~mutex() { HPX_ITT_SYNC_DESTROY(this); if (!queue_.empty()) { LERR_(fatal) << "lcos::local::mutex::~mutex: " << description_ << ": queue is not empty"; mutex_type::scoped_lock l(mtx_); while (!queue_.empty()) { threads::thread_id_type id = queue_.front().id_; queue_.front().id_ = 0; queue_.pop_front(); // we know that the id is actually the pointer to the thread LERR_(fatal) << "lcos::local::mutex::~mutex: " << description_ << ": pending thread: " << threads::get_thread_state_name(threads::get_thread_state(id)) << "(" << id << "): " << threads::get_thread_description(id); // forcefully abort thread, do not throw error_code ec(lightweight); threads::set_thread_state(id, threads::pending, threads::wait_abort, threads::thread_priority_default, ec); if (ec) { LERR_(fatal) << "lcos::local::mutex::~mutex: could not abort thread" << get_thread_state_name(threads::get_thread_state(id)) << "(" << id << "): " << threads::get_thread_state(id); } } } }
inline thread_state_enum set_active_state( thread_id_type const& thrd, thread_state_enum newstate, thread_state_ex_enum newstate_ex, thread_priority priority, thread_state previous_state) { if (HPX_UNLIKELY(!thrd)) { HPX_THROW_EXCEPTION(null_thread_id, "threads::detail::set_active_state", "NULL thread id encountered"); return terminated; } // make sure that the thread has not been suspended and set active again // in the mean time thread_state current_state = thrd->get_state(); if (thread_state_enum(current_state) == thread_state_enum(previous_state) && current_state != previous_state) { LTM_(warning) << "set_active_state: thread is still active, however " "it was non-active since the original set_state " "request was issued, aborting state change, thread(" << thrd.get() << "), description(" << thrd->get_description() << "), new state(" << get_thread_state_name(newstate) << ")"; return terminated; } // just retry, set_state will create new thread if target is still active error_code ec(lightweight); // do not throw detail::set_thread_state(thrd, newstate, newstate_ex, priority, std::size_t(-1), ec); return terminated; }
~counting_semaphore() { typename mutex_type::scoped_lock l(mtx_); if (!queue_.empty()) { LERR_(fatal) << "lcos::counting_semaphore::~counting_semaphore:" " queue is not empty, aborting threads"; while (!queue_.empty()) { threads::thread_id_type id = queue_.front().id_; queue_.front().id_ = 0; queue_.pop_front(); // we know that the id is actually the pointer to the thread LERR_(fatal) << "lcos::counting_semaphore::~counting_semaphore:" << " pending thread: " << get_thread_state_name(threads::get_thread_state(id)) << "(" << id << "): " << threads::get_thread_description(id); // forcefully abort thread, do not throw error_code ec(lightweight); threads::set_thread_state(id, threads::pending, threads::wait_abort, threads::thread_priority_default, ec); if (ec) { LERR_(fatal) << "lcos::counting_semaphore::~counting_semaphore:" << " could not abort thread: " << get_thread_state_name(threads::get_thread_state(id)) << "(" << id << "): " << threads::get_thread_description(id); } } } }
//-------------------------------------------------------------------------- static void display_thrinfo(const td_thrinfo_t &thi) { msg(" tid : %lx\n", thi.ti_tid); msg(" tls : %lx\n", (size_t)thi.ti_tls); msg(" entry : %lx\n", (size_t)thi.ti_startfunc); msg(" stackbase : %lx\n", (size_t)thi.ti_stkbase); msg(" stacksize : %lx\n", thi.ti_stksize); msg(" state : %s\n", get_thread_state_name(thi.ti_state)); msg(" suspended : %d\n", thi.ti_db_suspended); msg(" type : %s\n", get_thread_type_name(thi.ti_type)); msg(" priority : %d\n", thi.ti_pri); msg(" kernel pid : %d\n", thi.ti_lid); // lwpid_t msg(" signal mask : %lx\n", *(size_t*)&thi.ti_sigmask); msg(" traceme : %d\n", thi.ti_traceme); msg(" pending sg : %s\n", get_sigset_str(thi.ti_pending)); msg(" enabled ev : %s\n", get_thr_events_str(thi.ti_events)); }
inline void create_thread( policies::scheduler_base* scheduler, thread_init_data& data, threads::thread_id_type& id, thread_state_enum initial_state = pending, bool run_now = true, error_code& ec = throws) { // verify parameters switch (initial_state) { case pending: case pending_do_not_schedule: case suspended: break; default: { std::ostringstream strm; strm << "invalid initial state: " << get_thread_state_name(initial_state); HPX_THROWS_IF(ec, bad_parameter, "threads::detail::create_thread", strm.str()); return; } } #ifdef HPX_HAVE_THREAD_DESCRIPTION if (!data.description) { HPX_THROWS_IF(ec, bad_parameter, "threads::detail::create_thread", "description is nullptr"); return; } #endif thread_self* self = get_self_ptr(); #ifdef HPX_HAVE_THREAD_PARENT_REFERENCE if (nullptr == data.parent_id) { if (self) { data.parent_id = threads::get_self_id().get(); data.parent_phase = self->get_thread_phase(); } } if (0 == data.parent_locality_id) data.parent_locality_id = get_locality_id(); #endif if (nullptr == data.scheduler_base) data.scheduler_base = scheduler; // Pass critical priority from parent to child. if (self) { if (thread_priority_critical == threads::get_self_id()->get_priority()) data.priority = thread_priority_critical; } // create the new thread std::size_t num_thread = data.num_os_thread; scheduler->create_thread(data, &id, initial_state, run_now, ec, num_thread); LTM_(info) << "register_thread(" << id << "): initial_state(" << get_thread_state_name(initial_state) << "), " << "run_now(" << (run_now ? "true" : "false") #ifdef HPX_HAVE_THREAD_DESCRIPTION << "), description(" << data.description #endif << ")"; // potentially wake up waiting thread scheduler->do_some_work(num_thread); }
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 }
inline threads::thread_id_type create_thread( policies::scheduler_base* scheduler, thread_init_data& data, thread_state_enum initial_state = pending, bool run_now = true, error_code& ec = throws) { // verify parameters switch (initial_state) { case pending: case suspended: break; default: { hpx::util::osstream strm; strm << "invalid initial state: " << get_thread_state_name(initial_state); HPX_THROWS_IF(ec, bad_parameter, "threads::detail::create_thread", hpx::util::osstream_get_string(strm)); return invalid_thread_id; } } #if HPX_THREAD_MAINTAIN_DESCRIPTION if (0 == data.description) { HPX_THROWS_IF(ec, bad_parameter, "threads::detail::create_thread", "description is NULL"); return invalid_thread_id; } #endif #if HPX_THREAD_MAINTAIN_PARENT_REFERENCE if (0 == data.parent_id) { thread_self* self = get_self_ptr(); if (self) { data.parent_id = threads::get_self_id().get(); data.parent_phase = self->get_thread_phase(); } } if (0 == data.parent_locality_id) data.parent_locality_id = get_locality_id(); #endif if (0 == data.scheduler_base) data.scheduler_base = scheduler; // create the new thread thread_id_type newid = scheduler->create_thread( data, initial_state, run_now, ec, data.num_os_thread); LTM_(info) << "register_thread(" << newid << "): initial_state(" << get_thread_state_name(initial_state) << "), " << "run_now(" << (run_now ? "true" : "false") #if HPX_THREAD_MAINTAIN_DESCRIPTION << "), description(" << data.description #endif << ")"; return newid; }
inline thread_state set_thread_state( thread_id_type const& thrd, thread_state_enum new_state, thread_state_ex_enum new_state_ex, thread_priority priority, std::size_t thread_num, error_code& ec) { if (HPX_UNLIKELY(!thrd)) { HPX_THROWS_IF(ec, null_thread_id, "threads::detail::set_thread_state", "NULL thread id encountered"); return thread_state(unknown); } // set_state can't be used to force a thread into active state if (new_state == threads::active) { std::ostringstream strm; strm << "invalid new state: " << get_thread_state_name(new_state); HPX_THROWS_IF(ec, bad_parameter, "threads::detail::set_thread_state", strm.str()); return thread_state(unknown); } // we know that the id is actually the pointer to the thread if (!thrd) { if (&ec != &throws) ec = make_success_code(); return thread_state(terminated); // this thread has already been terminated } thread_state previous_state; do { // action depends on the current state previous_state = thrd->get_state(); thread_state_enum previous_state_val = previous_state; // nothing to do here if the state doesn't change if (new_state == previous_state_val) { LTM_(warning) << "set_thread_state: old thread state is the same as new " "thread state, aborting state change, thread(" << thrd.get() << "), description(" << thrd->get_description() << "), new state(" << get_thread_state_name(new_state) << ")"; if (&ec != &throws) ec = make_success_code(); return thread_state(new_state); } // the thread to set the state for is currently running, so we // schedule another thread to execute the pending set_state switch (previous_state_val) { case active: { // schedule a new thread to set the state LTM_(warning) << "set_thread_state: thread is currently active, scheduling " "new thread, thread(" << thrd.get() << "), description(" << thrd->get_description() << "), new state(" << get_thread_state_name(new_state) << ")"; thread_init_data data( boost::bind(&set_active_state, thrd, new_state, new_state_ex, priority, previous_state), "set state for active thread", 0, priority); create_work(thrd->get_scheduler_base(), data, pending, ec); if (&ec != &throws) ec = make_success_code(); return previous_state; // done } break; case terminated: { LTM_(warning) << "set_thread_state: thread is terminated, aborting state " "change, thread(" << thrd.get() << "), description(" << thrd->get_description() << "), new state(" << get_thread_state_name(new_state) << ")"; if (&ec != &throws) ec = make_success_code(); // If the thread has been terminated while this set_state was // pending nothing has to be done anymore. return previous_state; } break; case pending: if (suspended == new_state) { // we do not allow explicit resetting of a state to suspended // without the thread being executed. std::ostringstream strm; strm << "set_thread_state: invalid new state, can't demote a " "pending thread, " << "thread(" << thrd.get() << "), description(" << thrd->get_description() << "), new state(" << get_thread_state_name(new_state) << ")"; LTM_(fatal) << strm.str(); HPX_THROWS_IF(ec, bad_parameter, "threads::detail::set_thread_state", strm.str()); return thread_state(unknown); } break; case suspended: break; // fine, just set the new state default: HPX_ASSERT(false); // should not happen break; } // If the previous state was pending we are supposed to remove the // thread from the queue. But in order to avoid linearly looking // through the queue we defer this to the thread function, which // at some point will ignore this thread by simply skipping it // (if it's not pending anymore). LTM_(info) << "set_thread_state: thread(" << thrd.get() << "), " "description(" << thrd->get_description() << "), " "new state(" << get_thread_state_name(new_state) << "), " "old state(" << get_thread_state_name(previous_state_val) << ")"; // So all what we do here is to set the new state. if (thrd->restore_state(new_state, previous_state)) { thrd->set_state_ex(new_state_ex); break; } // state has changed since we fetched it from the thread, retry LTM_(error) << "set_thread_state: state has been changed since it was fetched, " "retrying, thread(" << thrd.get() << "), " "description(" << thrd->get_description() << "), " "new state(" << get_thread_state_name(new_state) << "), " "old state(" << get_thread_state_name(previous_state_val) << ")"; } while (true); if (new_state == pending) { // REVIEW: Passing a specific target thread may interfere with the // round robin queuing. thrd->get_scheduler_base()->schedule_thread(thrd.get(), thread_num, priority); thrd->get_scheduler_base()->do_some_work(thread_num); } if (&ec != &throws) ec = make_success_code(); return previous_state; }