1 // Copyright (c) 2007-2016 Hartmut Kaiser 2 // Copyright (c) 2008-2009 Chirag Dekate, Anshul Tandon 3 // Copyright (c) 2011 Bryce Lelbach 4 // 5 // Distributed under the Boost Software License, Version 1.0. (See accompanying 6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 8 #include <hpx/runtime/threads/thread_data.hpp> 9 10 #include <hpx/error_code.hpp> 11 #include <hpx/exception.hpp> 12 #include <hpx/throw_exception.hpp> 13 #include <hpx/runtime/naming/address.hpp> 14 #include <hpx/util/assert.hpp> 15 #include <hpx/util/function.hpp> 16 #include <hpx/util/register_locks.hpp> 17 #include <hpx/util/unlock_guard.hpp> 18 #if defined(HPX_HAVE_APEX) 19 #include <hpx/util/apex.hpp> 20 #endif 21 22 #include <cstddef> 23 #include <cstdint> 24 25 // #if HPX_DEBUG 26 // # define HPX_DEBUG_THREAD_POOL 1 27 // #endif 28 29 /////////////////////////////////////////////////////////////////////////////// 30 namespace hpx { namespace threads 31 { 32 #ifdef HPX_DEBUG_THREAD_POOL 33 enum guard_value 34 { 35 initial_value = 0xcc, // memory has been initialized 36 freed_value = 0xdd // memory has been freed 37 }; 38 #endif 39 run_thread_exit_callbacks()40 void thread_data::run_thread_exit_callbacks() 41 { 42 mutex_type::scoped_lock l(this); 43 44 while(!exit_funcs_.empty()) 45 { 46 { 47 hpx::util::unlock_guard<mutex_type::scoped_lock> ul(l); 48 if(!exit_funcs_.back().empty()) 49 exit_funcs_.back()(); 50 } 51 exit_funcs_.pop_back(); 52 } 53 ran_exit_funcs_ = true; 54 } 55 add_thread_exit_callback(util::function_nonser<void ()> const & f)56 bool thread_data::add_thread_exit_callback( 57 util::function_nonser<void()> const& f) 58 { 59 mutex_type::scoped_lock l(this); 60 61 if (ran_exit_funcs_ || get_state().state() == terminated) 62 { 63 return false; 64 } 65 66 exit_funcs_.push_back(f); 67 68 return true; 69 } 70 free_thread_exit_callbacks()71 void thread_data::free_thread_exit_callbacks() 72 { 73 mutex_type::scoped_lock l(this); 74 75 // Exit functions should have been executed. 76 HPX_ASSERT(exit_funcs_.empty() || ran_exit_funcs_); 77 78 exit_funcs_.clear(); 79 } 80 interruption_point(bool throw_on_interrupt)81 bool thread_data::interruption_point(bool throw_on_interrupt) 82 { 83 // We do not protect enabled_interrupt_ and requested_interrupt_ 84 // from concurrent access here (which creates a benign data race) in 85 // order to avoid infinite recursion. This function is called by 86 // this_thread::suspend which causes problems if the lock would call 87 // suspend itself. 88 if (enabled_interrupt_ && requested_interrupt_) 89 { 90 // Verify that there are no more registered locks for this 91 // OS-thread. This will throw if there are still any locks 92 // held. 93 util::force_error_on_lock(); 94 95 // now interrupt this thread 96 if (throw_on_interrupt) 97 throw hpx::thread_interrupted(); 98 99 return true; 100 } 101 return false; 102 } 103 104 /////////////////////////////////////////////////////////////////////////// get_self()105 thread_self& get_self() 106 { 107 thread_self* p = get_self_ptr(); 108 if (HPX_UNLIKELY(p == nullptr)) 109 { 110 HPX_THROW_EXCEPTION(null_thread_id, "threads::get_self", 111 "null thread id encountered (is this executed on a HPX-thread?)"); 112 } 113 return *p; 114 } 115 get_self_ptr()116 thread_self* get_self_ptr() 117 { 118 return thread_self::get_self(); 119 } 120 121 namespace detail 122 { set_self_ptr(thread_self * self)123 void set_self_ptr(thread_self* self) 124 { 125 thread_self::set_self(self); 126 } 127 } 128 get_ctx_ptr()129 thread_self::impl_type* get_ctx_ptr() 130 { 131 using hpx::threads::coroutines::detail::coroutine_accessor; 132 return coroutine_accessor::get_impl(get_self()); 133 } 134 get_self_ptr_checked(error_code & ec)135 thread_self* get_self_ptr_checked(error_code& ec) 136 { 137 thread_self* p = thread_self::get_self(); 138 139 if (HPX_UNLIKELY(p == nullptr)) 140 { 141 HPX_THROWS_IF(ec, null_thread_id, "threads::get_self_ptr_checked", 142 "null thread id encountered (is this executed on a HPX-thread?)"); 143 return nullptr; 144 } 145 146 if (&ec != &throws) 147 ec = make_success_code(); 148 149 return p; 150 } 151 get_self_id()152 thread_id_type get_self_id() 153 { 154 thread_self* self = get_self_ptr(); 155 if (HPX_LIKELY(nullptr != self)) 156 return self->get_thread_id(); 157 158 return threads::invalid_thread_id; 159 } 160 get_self_stacksize()161 std::size_t get_self_stacksize() 162 { 163 thread_id_type id = get_self_id(); 164 return id ? id->get_stack_size() : 0; 165 } 166 167 #ifndef HPX_HAVE_THREAD_PARENT_REFERENCE get_parent_id()168 thread_id_type get_parent_id() 169 { 170 return threads::invalid_thread_id; 171 } 172 get_parent_phase()173 std::size_t get_parent_phase() 174 { 175 return 0; 176 } 177 get_parent_locality_id()178 std::uint32_t get_parent_locality_id() 179 { 180 return naming::invalid_locality_id; 181 } 182 #else get_parent_id()183 thread_id_type get_parent_id() 184 { 185 thread_self* self = get_self_ptr(); 186 if (HPX_LIKELY(nullptr != self)) 187 return self->get_thread_id()->get_parent_thread_id(); 188 return threads::invalid_thread_id; 189 } 190 get_parent_phase()191 std::size_t get_parent_phase() 192 { 193 thread_self* self = get_self_ptr(); 194 if (HPX_LIKELY(nullptr != self)) 195 return self->get_thread_id()->get_parent_thread_phase(); 196 return 0; 197 } 198 get_parent_locality_id()199 std::uint32_t get_parent_locality_id() 200 { 201 thread_self* self = get_self_ptr(); 202 if (HPX_LIKELY(nullptr != self)) 203 return self->get_thread_id()->get_parent_locality_id(); 204 return naming::invalid_locality_id; 205 } 206 #endif 207 get_self_component_id()208 naming::address::address_type get_self_component_id() 209 { 210 #ifndef HPX_HAVE_THREAD_TARGET_ADDRESS 211 return 0; 212 #else 213 thread_self* self = get_self_ptr(); 214 if (HPX_LIKELY(nullptr != self)) 215 return self->get_thread_id()->get_component_id(); 216 return 0; 217 #endif 218 } 219 220 #if defined(HPX_HAVE_APEX) get_self_apex_data()221 apex_task_wrapper get_self_apex_data() 222 { 223 thread_self* self = get_self_ptr(); 224 if (HPX_LIKELY(nullptr != self)) 225 return self->get_apex_data(); 226 return nullptr; 227 } set_self_apex_data(apex_task_wrapper data)228 void set_self_apex_data(apex_task_wrapper data) 229 { 230 thread_self* self = get_self_ptr(); 231 if (HPX_LIKELY(nullptr != self)) 232 self->set_apex_data(data); 233 return; 234 } 235 #endif 236 }} 237