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