1 //  Copyright (c) 2007-2015 Hartmut Kaiser
2 //  Copyright (c)      2018 Thomas Heller
3 //  Copyright (c)      2011 Bryce Lelbach
4 //  Copyright (c) 2008-2009 Chirag Dekate, Anshul Tandon
5 //
6 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
7 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 
9 #ifndef HPX_RUNTIME_THREADS_THREAD_HELPERS_HPP
10 #define HPX_RUNTIME_THREADS_THREAD_HELPERS_HPP
11 
12 #include <hpx/config.hpp>
13 #include <hpx/exception_fwd.hpp>
14 #include <hpx/runtime/naming_fwd.hpp>
15 #include <hpx/runtime/threads_fwd.hpp>
16 #include <hpx/runtime/thread_pool_helpers.hpp>
17 #include <hpx/runtime/threads/policies/scheduler_mode.hpp>
18 #include <hpx/runtime/threads/thread_data_fwd.hpp>
19 #include <hpx/runtime/threads/thread_enums.hpp>
20 #include <hpx/util_fwd.hpp>
21 #include <hpx/util/unique_function.hpp>
22 #include <hpx/util/register_locks.hpp>
23 #include <hpx/util/steady_clock.hpp>
24 #include <hpx/util/thread_description.hpp>
25 
26 #include <atomic>
27 #include <chrono>
28 #include <cstddef>
29 #include <cstdint>
30 #include <type_traits>
31 #include <utility>
32 
33 ///////////////////////////////////////////////////////////////////////////////
34 namespace hpx { namespace threads
35 {
36     /// \cond NOINTERNAL
37     class thread_init_data;
38     /// \endcond
39 
40     ///////////////////////////////////////////////////////////////////////////
41     /// \brief  Set the thread state of the \a thread referenced by the
42     ///         thread_id \a id.
43     ///
44     /// \param id         [in] The thread id of the thread the state should
45     ///                   be modified for.
46     /// \param state      [in] The new state to be set for the thread
47     ///                   referenced by the \a id parameter.
48     /// \param stateex    [in] The new extended state to be set for the
49     ///                   thread referenced by the \a id parameter.
50     /// \param priority
51     /// \param ec         [in,out] this represents the error status on exit,
52     ///                   if this is pre-initialized to \a hpx#throws
53     ///                   the function will throw on error instead.
54     ///
55     /// \note             If the thread referenced by the parameter \a id
56     ///                   is in \a thread_state#active state this function
57     ///                   schedules a new thread which will set the state of
58     ///                   the thread as soon as its not active anymore. The
59     ///                   function returns \a thread_state#active in this case.
60     ///
61     /// \returns          This function returns the previous state of the
62     ///                   thread referenced by the \a id parameter. It will
63     ///                   return one of the values as defined by the
64     ///                   \a thread_state enumeration. If the
65     ///                   thread is not known to the thread-manager the
66     ///                   return value will be \a thread_state#unknown.
67     ///
68     /// \note             As long as \a ec is not pre-initialized to
69     ///                   \a hpx#throws this function doesn't
70     ///                   throw but returns the result code using the
71     ///                   parameter \a ec. Otherwise it throws an instance
72     ///                   of hpx#exception.
73     HPX_API_EXPORT thread_state set_thread_state(thread_id_type const& id,
74         thread_state_enum state = pending,
75         thread_state_ex_enum stateex = wait_signaled,
76         thread_priority priority = thread_priority_normal,
77         hpx::error_code& ec = throws);
78 
79     ///////////////////////////////////////////////////////////////////////
80     /// \brief  Set the thread state of the \a thread referenced by the
81     ///         thread_id \a id.
82     ///
83     /// Set a timer to set the state of the given \a thread to the given
84     /// new value after it expired (at the given time)
85     ///
86     /// \param id         [in] The thread id of the thread the state should
87     ///                   be modified for.
88     /// \param abs_time   [in] Absolute point in time for the new thread to be
89     ///                   run
90     /// \param started    [in,out] A helper variable allowing to track the
91     ///                   state of the timer helper thread
92     /// \param state      [in] The new state to be set for the thread
93     ///                   referenced by the \a id parameter.
94     /// \param stateex    [in] The new extended state to be set for the
95     ///                   thread referenced by the \a id parameter.
96     /// \param priority
97     /// \param ec         [in,out] this represents the error status on exit,
98     ///                   if this is pre-initialized to \a hpx#throws
99     ///                   the function will throw on error instead.
100     ///
101     /// \returns
102     ///
103     /// \note             As long as \a ec is not pre-initialized to
104     ///                   \a hpx#throws this function doesn't
105     ///                   throw but returns the result code using the
106     ///                   parameter \a ec. Otherwise it throws an instance
107     ///                   of hpx#exception.
108     HPX_API_EXPORT thread_id_type set_thread_state(thread_id_type const& id,
109         util::steady_time_point const& abs_time,
110         std::atomic<bool>* started,
111         thread_state_enum state = pending,
112         thread_state_ex_enum stateex = wait_timeout,
113         thread_priority priority = thread_priority_normal,
114         error_code& ec = throws);
115 
set_thread_state(thread_id_type const & id,util::steady_time_point const & abs_time,thread_state_enum state=pending,thread_state_ex_enum stateex=wait_timeout,thread_priority priority=thread_priority_normal,error_code &=throws)116     inline thread_id_type set_thread_state(thread_id_type const& id,
117         util::steady_time_point const& abs_time,
118         thread_state_enum state = pending,
119         thread_state_ex_enum stateex = wait_timeout,
120         thread_priority priority = thread_priority_normal,
121         error_code& /*ec*/ = throws)
122     {
123         return set_thread_state(id, abs_time, nullptr, state, stateex,
124             priority, throws);
125     }
126 
127     ///////////////////////////////////////////////////////////////////////////
128     /// \brief  Set the thread state of the \a thread referenced by the
129     ///         thread_id \a id.
130     ///
131     /// Set a timer to set the state of the given \a thread to the given
132     /// new value after it expired (after the given duration)
133     ///
134     /// \param id         [in] The thread id of the thread the state should
135     ///                   be modified for.
136     /// \param rel_time   [in] Time duration after which the new thread should
137     ///                   be run
138     /// \param state      [in] The new state to be set for the thread
139     ///                   referenced by the \a id parameter.
140     /// \param stateex    [in] The new extended state to be set for the
141     ///                   thread referenced by the \a id parameter.
142     /// \param priority
143     /// \param ec         [in,out] this represents the error status on exit,
144     ///                   if this is pre-initialized to \a hpx#throws
145     ///                   the function will throw on error instead.
146     ///
147     /// \returns
148     ///
149     /// \note             As long as \a ec is not pre-initialized to
150     ///                   \a hpx#throws this function doesn't
151     ///                   throw but returns the result code using the
152     ///                   parameter \a ec. Otherwise it throws an instance
153     ///                   of hpx#exception.
set_thread_state(thread_id_type const & id,util::steady_duration const & rel_time,thread_state_enum state=pending,thread_state_ex_enum stateex=wait_timeout,thread_priority priority=thread_priority_normal,error_code & ec=throws)154     inline thread_id_type set_thread_state(thread_id_type const& id,
155         util::steady_duration const& rel_time,
156         thread_state_enum state = pending,
157         thread_state_ex_enum stateex = wait_timeout,
158         thread_priority priority = thread_priority_normal,
159         error_code& ec = throws)
160     {
161         return set_thread_state(id, rel_time.from_now(), state, stateex,
162             priority, ec);
163     }
164 
165     ///////////////////////////////////////////////////////////////////////////
166     /// The function get_thread_description is part of the thread related API
167     /// allows to query the description of one of the threads known to the
168     /// thread-manager.
169     ///
170     /// \param id         [in] The thread id of the thread being queried.
171     /// \param ec         [in,out] this represents the error status on exit,
172     ///                   if this is pre-initialized to \a hpx#throws
173     ///                   the function will throw on error instead.
174     ///
175     /// \returns          This function returns the description of the
176     ///                   thread referenced by the \a id parameter. If the
177     ///                   thread is not known to the thread-manager the return
178     ///                   value will be the string "<unknown>".
179     ///
180     /// \note             As long as \a ec is not pre-initialized to
181     ///                   \a hpx#throws this function doesn't
182     ///                   throw but returns the result code using the
183     ///                   parameter \a ec. Otherwise it throws an instance
184     ///                   of hpx#exception.
185     HPX_API_EXPORT util::thread_description get_thread_description(
186         thread_id_type const& id, error_code& ec = throws);
187     HPX_API_EXPORT util::thread_description set_thread_description(
188         thread_id_type const& id,
189         util::thread_description const& desc = util::thread_description(),
190         error_code& ec = throws);
191 
192     HPX_API_EXPORT util::thread_description get_thread_lco_description(
193         thread_id_type const& id, error_code& ec = throws);
194     HPX_API_EXPORT util::thread_description set_thread_lco_description(
195         thread_id_type const& id,
196         util::thread_description const& desc = util::thread_description(),
197         error_code& ec = throws);
198 
199     ///////////////////////////////////////////////////////////////////////////
200     /// The function get_thread_backtrace is part of the thread related API
201     /// allows to query the currently stored thread back trace (which is
202     /// captured during thread suspension).
203     ///
204     /// \param id         [in] The thread id of the thread being queried.
205     /// \param ec         [in,out] this represents the error status on exit,
206     ///                   if this is pre-initialized to \a hpx#throws
207     ///                   the function will throw on error instead.
208     ///
209     /// \returns          This function returns the currently captured stack
210     ///                   back trace of the thread referenced by the \a id
211     ///                   parameter. If the thread is not known to the
212     ///                   thread-manager the return value will be the zero.
213     ///
214     /// \note             As long as \a ec is not pre-initialized to
215     ///                   \a hpx#throws this function doesn't
216     ///                   throw but returns the result code using the
217     ///                   parameter \a ec. Otherwise it throws an instance
218     ///                   of hpx#exception.
219 #ifdef HPX_HAVE_THREAD_FULLBACKTRACE_ON_SUSPENSION
220     HPX_API_EXPORT char const* get_thread_backtrace(
221         thread_id_type const& id, error_code& ec = throws);
222     HPX_API_EXPORT char const* set_thread_backtrace(
223         thread_id_type const& id, char const* bt = nullptr,
224         error_code& ec = throws);
225 #else
226 #if !defined(DOXYGEN)
227     HPX_API_EXPORT util::backtrace const* get_thread_backtrace(
228         thread_id_type const& id, error_code& ec = throws);
229     HPX_API_EXPORT util::backtrace const* set_thread_backtrace(
230         thread_id_type const& id, util::backtrace const* bt = nullptr,
231         error_code& ec = throws);
232 #endif
233 #endif
234 
235     ///////////////////////////////////////////////////////////////////////////
236     /// The function get_thread_state is part of the thread related API. It
237     /// queries the state of one of the threads known to the thread-manager.
238     ///
239     /// \param id         [in] The thread id of the thread the state should
240     ///                   be modified for.
241     /// \param ec         [in,out] this represents the error status on exit,
242     ///                   if this is pre-initialized to \a hpx#throws
243     ///                   the function will throw on error instead.
244     ///
245     /// \returns          This function returns the thread state of the
246     ///                   thread referenced by the \a id parameter. If the
247     ///                   thread is not known to the thread-manager the return
248     ///                   value will be \a terminated.
249     ///
250     /// \note             As long as \a ec is not pre-initialized to
251     ///                   \a hpx#throws this function doesn't
252     ///                   throw but returns the result code using the
253     ///                   parameter \a ec. Otherwise it throws an instance
254     ///                   of hpx#exception.
255     HPX_API_EXPORT thread_state get_thread_state(thread_id_type const& id,
256         error_code& ec = throws);
257 
258     ///////////////////////////////////////////////////////////////////////////
259     /// The function get_thread_phase is part of the thread related API.
260     /// It queries the phase of one of the threads known to the thread-manager.
261     ///
262     /// \param id         [in] The thread id of the thread the phase should
263     ///                   be modified for.
264     /// \param ec         [in,out] this represents the error status on exit,
265     ///                   if this is pre-initialized to \a hpx#throws
266     ///                   the function will throw on error instead.
267     ///
268     /// \returns          This function returns the thread phase of the
269     ///                   thread referenced by the \a id parameter. If the
270     ///                   thread is not known to the thread-manager the return
271     ///                   value will be ~0.
272     ///
273     /// \note             As long as \a ec is not pre-initialized to
274     ///                   \a hpx#throws this function doesn't
275     ///                   throw but returns the result code using the
276     ///                   parameter \a ec. Otherwise it throws an instance
277     ///                   of hpx#exception.
278     HPX_API_EXPORT std::size_t get_thread_phase(thread_id_type const& id,
279         error_code& ec = throws);
280 
281     ///////////////////////////////////////////////////////////////////////////
282     // Return the number of the NUMA node the current thread is running on
283     HPX_API_EXPORT std::size_t get_numa_node_number();
284 
285     ///////////////////////////////////////////////////////////////////////////
286     /// Returns whether the given thread can be interrupted at this point.
287     ///
288     /// \param id         [in] The thread id of the thread which should be
289     ///                   queried.
290     /// \param ec         [in,out] this represents the error status on exit,
291     ///                   if this is pre-initialized to \a hpx#throws
292     ///                   the function will throw on error instead.
293     ///
294     /// \returns          This function returns \a true if the given thread
295     ///                   can be interrupted at this point in time. It will
296     ///                   return \a false otherwise.
297     ///
298     /// \note             As long as \a ec is not pre-initialized to
299     ///                   \a hpx#throws this function doesn't
300     ///                   throw but returns the result code using the
301     ///                   parameter \a ec. Otherwise it throws an instance
302     ///                   of hpx#exception.
303     HPX_API_EXPORT bool get_thread_interruption_enabled(thread_id_type const& id,
304         error_code& ec = throws);
305 
306     /// Set whether the given thread can be interrupted at this point.
307     ///
308     /// \param id         [in] The thread id of the thread which should
309     ///                   receive the new value.
310     /// \param enable     [in] This value will determine the new interruption
311     ///                   enabled status for the given thread.
312     /// \param ec         [in,out] this represents the error status on exit,
313     ///                   if this is pre-initialized to \a hpx#throws
314     ///                   the function will throw on error instead.
315     ///
316     /// \returns          This function returns the previous value of
317     ///                   whether the given thread could have been interrupted.
318     ///
319     /// \note             As long as \a ec is not pre-initialized to
320     ///                   \a hpx#throws this function doesn't
321     ///                   throw but returns the result code using the
322     ///                   parameter \a ec. Otherwise it throws an instance
323     ///                   of hpx#exception.
324     HPX_API_EXPORT bool set_thread_interruption_enabled(thread_id_type const& id,
325         bool enable, error_code& ec = throws);
326 
327     /// Returns whether the given thread has been flagged for interruption.
328     ///
329     /// \param id         [in] The thread id of the thread which should be
330     ///                   queried.
331     /// \param ec         [in,out] this represents the error status on exit,
332     ///                   if this is pre-initialized to \a hpx#throws
333     ///                   the function will throw on error instead.
334     ///
335     /// \returns          This function returns \a true if the given thread
336     ///                   was flagged for interruption. It will return
337     ///                   \a false otherwise.
338     ///
339     /// \note             As long as \a ec is not pre-initialized to
340     ///                   \a hpx#throws this function doesn't
341     ///                   throw but returns the result code using the
342     ///                   parameter \a ec. Otherwise it throws an instance
343     ///                   of hpx#exception.
344     HPX_API_EXPORT bool get_thread_interruption_requested(thread_id_type const& id,
345         error_code& ec = throws);
346 
347     /// Flag the given thread for interruption.
348     ///
349     /// \param id         [in] The thread id of the thread which should be
350     ///                   interrupted.
351     /// \param flag       [in] The flag encodes whether the thread should be
352     ///                   interrupted (if it is \a true), or 'uninterrupted'
353     ///                   (if it is \a false).
354     /// \param ec         [in,out] this represents the error status on exit,
355     ///                   if this is pre-initialized to \a hpx#throws
356     ///                   the function will throw on error instead.
357     ///
358     /// \note             As long as \a ec is not pre-initialized to
359     ///                   \a hpx#throws this function doesn't
360     ///                   throw but returns the result code using the
361     ///                   parameter \a ec. Otherwise it throws an instance
362     ///                   of hpx#exception.
363     HPX_API_EXPORT void interrupt_thread(thread_id_type const& id, bool flag,
364         error_code& ec = throws);
365 
interrupt_thread(thread_id_type const & id,error_code & ec=throws)366     inline void interrupt_thread(thread_id_type const& id, error_code& ec = throws)
367     {
368         interrupt_thread(id, true, ec);
369     }
370 
371     ///////////////////////////////////////////////////////////////////////////
372     /// Interrupt the current thread at this point if it was canceled. This
373     /// will throw a thread_interrupted exception, which will cancel the thread.
374     ///
375     /// \param id         [in] The thread id of the thread which should be
376     ///                   interrupted.
377     /// \param ec         [in,out] this represents the error status on exit,
378     ///                   if this is pre-initialized to \a hpx#throws
379     ///                   the function will throw on error instead.
380     ///
381     /// \note             As long as \a ec is not pre-initialized to
382     ///                   \a hpx#throws this function doesn't
383     ///                   throw but returns the result code using the
384     ///                   parameter \a ec. Otherwise it throws an instance
385     ///                   of hpx#exception.
386     HPX_API_EXPORT void interruption_point(thread_id_type const& id,
387         error_code& ec = throws);
388 
389     ///////////////////////////////////////////////////////////////////////////
390     /// Return priority of the given thread
391     ///
392     /// \param id         [in] The thread id of the thread whose priority
393     ///                   is queried.
394     /// \param ec         [in,out] this represents the error status on exit,
395     ///                   if this is pre-initialized to \a hpx#throws
396     ///                   the function will throw on error instead.
397     ///
398     /// \note             As long as \a ec is not pre-initialized to
399     ///                   \a hpx#throws this function doesn't
400     ///                   throw but returns the result code using the
401     ///                   parameter \a ec. Otherwise it throws an instance
402     ///                   of hpx#exception.
403     HPX_API_EXPORT threads::thread_priority get_thread_priority(
404         thread_id_type const& id, error_code& ec = throws);
405 
406     ///////////////////////////////////////////////////////////////////////////
407     /// Return stack size of the given thread
408     ///
409     /// \param id         [in] The thread id of the thread whose priority
410     ///                   is queried.
411     /// \param ec         [in,out] this represents the error status on exit,
412     ///                   if this is pre-initialized to \a hpx#throws
413     ///                   the function will throw on error instead.
414     ///
415     /// \note             As long as \a ec is not pre-initialized to
416     ///                   \a hpx#throws this function doesn't
417     ///                   throw but returns the result code using the
418     ///                   parameter \a ec. Otherwise it throws an instance
419     ///                   of hpx#exception.
420     HPX_API_EXPORT std::ptrdiff_t get_stack_size(
421         thread_id_type const& id, error_code& ec = throws);
422 
423     ///////////////////////////////////////////////////////////////////////////
424     /// \cond NOINTERNAL
425     HPX_API_EXPORT void run_thread_exit_callbacks(thread_id_type const& id,
426         error_code& ec = throws);
427 
428     HPX_API_EXPORT bool add_thread_exit_callback(thread_id_type const& id,
429         util::function_nonser<void()> const& f, error_code& ec = throws);
430 
431     HPX_API_EXPORT void free_thread_exit_callbacks(thread_id_type const& id,
432         error_code& ec = throws);
433 
434     ///////////////////////////////////////////////////////////////////////////
435     HPX_API_EXPORT std::size_t get_thread_data(thread_id_type const& id,
436         error_code& ec = throws);
437 
438     HPX_API_EXPORT std::size_t set_thread_data(thread_id_type const& id,
439         std::size_t data, error_code& ec = throws);
440 
441     HPX_API_EXPORT std::size_t& get_continuation_recursion_count();
442     HPX_API_EXPORT void reset_continuation_recursion_count();
443     /// \endcond
444 
445     /// Returns a reference to the executor which was used to create
446     /// the given thread.
447     ///
448     /// \throws If <code>&ec != &throws</code>, never throws, but will set \a ec
449     ///         to an appropriate value when an error occurs. Otherwise, this
450     ///         function will throw an \a hpx#exception with an error code of
451     ///         \a hpx#yield_aborted if it is signaled with \a wait_aborted.
452     ///         If called outside of a HPX-thread, this function will throw
453     ///         an \a hpx#exception with an error code of \a hpx::null_thread_id.
454     ///         If this function is called while the thread-manager is not
455     ///         running, it will throw an \a hpx#exception with an error code of
456     ///         \a hpx#invalid_status.
457     ///
458     HPX_API_EXPORT threads::executors::current_executor
459         get_executor(thread_id_type const& id, error_code& ec = throws);
460 
461     /// Returns a pointer to the pool that was used to run the current thread
462     ///
463     /// \throws If <code>&ec != &throws</code>, never throws, but will set \a ec
464     ///         to an appropriate value when an error occurs. Otherwise, this
465     ///         function will throw an \a hpx#exception with an error code of
466     ///         \a hpx#yield_aborted if it is signaled with \a wait_aborted.
467     ///         If called outside of a HPX-thread, this function will throw
468     ///         an \a hpx#exception with an error code of \a hpx::null_thread_id.
469     ///         If this function is called while the thread-manager is not
470     ///         running, it will throw an \a hpx#exception with an error code of
471     ///         \a hpx#invalid_status.
472     HPX_EXPORT threads::thread_pool_base*
473         get_pool(thread_id_type const& id, error_code& ec = throws);
474 
475     /// \cond NOINTERNAL
476     /// Reset internal (round robin) thread distribution scheme
477     HPX_API_EXPORT void reset_thread_distribution();
478 
479     /// Set the new scheduler mode
480     HPX_API_EXPORT void set_scheduler_mode(threads::policies::scheduler_mode);
481     /// \endcond
482 }}
483 
484 namespace hpx { namespace this_thread
485 {
486     ///////////////////////////////////////////////////////////////////////////
487     /// The function \a suspend will return control to the thread manager
488     /// (suspends the current thread). It sets the new state of this thread
489     /// to the thread state passed as the parameter.
490     ///
491     /// \note Must be called from within a HPX-thread.
492     ///
493     /// \throws If <code>&ec != &throws</code>, never throws, but will set \a ec
494     ///         to an appropriate value when an error occurs. Otherwise, this
495     ///         function will throw an \a hpx#exception with an error code of
496     ///         \a hpx#yield_aborted if it is signaled with \a wait_aborted.
497     ///         If called outside of a HPX-thread, this function will throw
498     ///         an \a hpx#exception with an error code of \a hpx::null_thread_id.
499     ///         If this function is called while the thread-manager is not
500     ///         running, it will throw an \a hpx#exception with an error code of
501     ///         \a hpx#invalid_status.
502     ///
503     HPX_API_EXPORT threads::thread_state_ex_enum suspend(
504         threads::thread_state_enum state, threads::thread_id_type const& id,
505         util::thread_description const& description =
506             util::thread_description("this_thread::suspend"),
507         error_code& ec = throws);
508 
509     /// The function \a suspend will return control to the thread manager
510     /// (suspends the current thread). It sets the new state of this thread
511     /// to the thread state passed as the parameter.
512     ///
513     /// \note Must be called from within a HPX-thread.
514     ///
515     /// \throws If <code>&ec != &throws</code>, never throws, but will set \a ec
516     ///         to an appropriate value when an error occurs. Otherwise, this
517     ///         function will throw an \a hpx#exception with an error code of
518     ///         \a hpx#yield_aborted if it is signaled with \a wait_aborted.
519     ///         If called outside of a HPX-thread, this function will throw
520     ///         an \a hpx#exception with an error code of \a hpx::null_thread_id.
521     ///         If this function is called while the thread-manager is not
522     ///         running, it will throw an \a hpx#exception with an error code of
523     ///         \a hpx#invalid_status.
524     ///
suspend(threads::thread_state_enum state=threads::pending,util::thread_description const & description=util::thread_description ("this_thread::suspend"),error_code & ec=throws)525     inline threads::thread_state_ex_enum suspend(
526         threads::thread_state_enum state = threads::pending,
527         util::thread_description const& description =
528             util::thread_description("this_thread::suspend"),
529         error_code& ec = throws)
530     {
531         return suspend(state, threads::invalid_thread_id, description, ec);
532     }
533 
534     /// The function \a suspend will return control to the thread manager
535     /// (suspends the current thread). It sets the new state of this thread
536     /// to \a suspended and schedules a wakeup for this threads at the given
537     /// time.
538     ///
539     /// \note Must be called from within a HPX-thread.
540     ///
541     /// \throws If <code>&ec != &throws</code>, never throws, but will set \a ec
542     ///         to an appropriate value when an error occurs. Otherwise, this
543     ///         function will throw an \a hpx#exception with an error code of
544     ///         \a hpx#yield_aborted if it is signaled with \a wait_aborted.
545     ///         If called outside of a HPX-thread, this function will throw
546     ///         an \a hpx#exception with an error code of \a hpx::null_thread_id.
547     ///         If this function is called while the thread-manager is not
548     ///         running, it will throw an \a hpx#exception with an error code of
549     ///         \a hpx#invalid_status.
550     ///
551     HPX_API_EXPORT threads::thread_state_ex_enum suspend(
552         util::steady_time_point const& abs_time,
553         threads::thread_id_type const& id,
554         util::thread_description const& description =
555             util::thread_description("this_thread::suspend"),
556         error_code& ec = throws);
557 
558     /// The function \a suspend will return control to the thread manager
559     /// (suspends the current thread). It sets the new state of this thread
560     /// to \a suspended and schedules a wakeup for this threads at the given
561     /// time.
562     ///
563     /// \note Must be called from within a HPX-thread.
564     ///
565     /// \throws If <code>&ec != &throws</code>, never throws, but will set \a ec
566     ///         to an appropriate value when an error occurs. Otherwise, this
567     ///         function will throw an \a hpx#exception with an error code of
568     ///         \a hpx#yield_aborted if it is signaled with \a wait_aborted.
569     ///         If called outside of a HPX-thread, this function will throw
570     ///         an \a hpx#exception with an error code of \a hpx::null_thread_id.
571     ///         If this function is called while the thread-manager is not
572     ///         running, it will throw an \a hpx#exception with an error code of
573     ///         \a hpx#invalid_status.
574     ///
suspend(util::steady_time_point const & abs_time,util::thread_description const & description=util::thread_description ("this_thread::suspend"),error_code & ec=throws)575     inline threads::thread_state_ex_enum suspend(
576         util::steady_time_point const& abs_time,
577         util::thread_description const& description =
578             util::thread_description("this_thread::suspend"),
579         error_code& ec = throws)
580     {
581         return suspend(abs_time, threads::invalid_thread_id, description, ec);
582     }
583 
584     /// The function \a suspend will return control to the thread manager
585     /// (suspends the current thread). It sets the new state of this thread
586     /// to \a suspended and schedules a wakeup for this threads after the given
587     /// duration.
588     ///
589     /// \note Must be called from within a HPX-thread.
590     ///
591     /// \throws If <code>&ec != &throws</code>, never throws, but will set \a ec
592     ///         to an appropriate value when an error occurs. Otherwise, this
593     ///         function will throw an \a hpx#exception with an error code of
594     ///         \a hpx#yield_aborted if it is signaled with \a wait_aborted.
595     ///         If called outside of a HPX-thread, this function will throw
596     ///         an \a hpx#exception with an error code of \a hpx::null_thread_id.
597     ///         If this function is called while the thread-manager is not
598     ///         running, it will throw an \a hpx#exception with an error code of
599     ///         \a hpx#invalid_status.
600     ///
suspend(util::steady_duration const & rel_time,util::thread_description const & description=util::thread_description ("this_thread::suspend"),error_code & ec=throws)601     inline threads::thread_state_ex_enum suspend(
602         util::steady_duration const& rel_time,
603         util::thread_description const& description =
604             util::thread_description("this_thread::suspend"),
605         error_code& ec = throws)
606     {
607         return suspend(rel_time.from_now(), threads::invalid_thread_id,
608             description, ec);
609     }
610 
611     /// The function \a suspend will return control to the thread manager
612     /// (suspends the current thread). It sets the new state of this thread
613     /// to \a suspended and schedules a wakeup for this threads after the given
614     /// duration.
615     ///
616     /// \note Must be called from within a HPX-thread.
617     ///
618     /// \throws If <code>&ec != &throws</code>, never throws, but will set \a ec
619     ///         to an appropriate value when an error occurs. Otherwise, this
620     ///         function will throw an \a hpx#exception with an error code of
621     ///         \a hpx#yield_aborted if it is signaled with \a wait_aborted.
622     ///         If called outside of a HPX-thread, this function will throw
623     ///         an \a hpx#exception with an error code of \a hpx::null_thread_id.
624     ///         If this function is called while the thread-manager is not
625     ///         running, it will throw an \a hpx#exception with an error code of
626     ///         \a hpx#invalid_status.
627     ///
suspend(util::steady_duration const & rel_time,threads::thread_id_type const & id,util::thread_description const & description=util::thread_description ("this_thread::suspend"),error_code & ec=throws)628     inline threads::thread_state_ex_enum suspend(
629         util::steady_duration const& rel_time,
630         threads::thread_id_type const& id,
631         util::thread_description const& description =
632             util::thread_description("this_thread::suspend"),
633         error_code& ec = throws)
634     {
635         return suspend(rel_time.from_now(), id, description, ec);
636     }
637 
638     /// The function \a suspend will return control to the thread manager
639     /// (suspends the current thread). It sets the new state of this thread
640     /// to \a suspended and schedules a wakeup for this threads after the given
641     /// time (specified in milliseconds).
642     ///
643     /// \note Must be called from within a HPX-thread.
644     ///
645     /// \throws If <code>&ec != &throws</code>, never throws, but will set \a ec
646     ///         to an appropriate value when an error occurs. Otherwise, this
647     ///         function will throw an \a hpx#exception with an error code of
648     ///         \a hpx#yield_aborted if it is signaled with \a wait_aborted.
649     ///         If called outside of a HPX-thread, this function will throw
650     ///         an \a hpx#exception with an error code of \a hpx::null_thread_id.
651     ///         If this function is called while the thread-manager is not
652     ///         running, it will throw an \a hpx#exception with an error code of
653     ///         \a hpx#invalid_status.
654     ///
suspend(std::uint64_t ms,util::thread_description const & description=util::thread_description ("this_thread::suspend"),error_code & ec=throws)655     inline threads::thread_state_ex_enum suspend(std::uint64_t ms,
656         util::thread_description const& description =
657             util::thread_description("this_thread::suspend"),
658         error_code& ec = throws)
659     {
660         return suspend(std::chrono::milliseconds(ms), threads::invalid_thread_id,
661             description, ec);
662     }
663 
664     /// Returns a reference to the executor which was used to create the current
665     /// thread.
666     ///
667     /// \throws If <code>&ec != &throws</code>, never throws, but will set \a ec
668     ///         to an appropriate value when an error occurs. Otherwise, this
669     ///         function will throw an \a hpx#exception with an error code of
670     ///         \a hpx#yield_aborted if it is signaled with \a wait_aborted.
671     ///         If called outside of a HPX-thread, this function will throw
672     ///         an \a hpx#exception with an error code of \a hpx::null_thread_id.
673     ///         If this function is called while the thread-manager is not
674     ///         running, it will throw an \a hpx#exception with an error code of
675     ///         \a hpx#invalid_status.
676     ///
677     HPX_EXPORT threads::executors::current_executor
678         get_executor(error_code& ec = throws);
679 
680     /// Returns a pointer to the pool that was used to run the current thread
681     ///
682     /// \throws If <code>&ec != &throws</code>, never throws, but will set \a ec
683     ///         to an appropriate value when an error occurs. Otherwise, this
684     ///         function will throw an \a hpx#exception with an error code of
685     ///         \a hpx#yield_aborted if it is signaled with \a wait_aborted.
686     ///         If called outside of a HPX-thread, this function will throw
687     ///         an \a hpx#exception with an error code of \a hpx::null_thread_id.
688     ///         If this function is called while the thread-manager is not
689     ///         running, it will throw an \a hpx#exception with an error code of
690     ///         \a hpx#invalid_status.
691     HPX_EXPORT threads::thread_pool_base* get_pool(error_code& ec = throws);
692 
693     /// \cond NOINTERNAL
694     // returns the remaining available stack space
695     HPX_EXPORT std::ptrdiff_t get_available_stack_space();
696 
697     // returns whether the remaining stack-space is at least as large as
698     // requested
699     HPX_EXPORT bool has_sufficient_stack_space(
700         std::size_t space_needed = 8 * HPX_THREADS_STACK_OVERHEAD);
701     /// \endcond
702 }}
703 
704 /// \cond NOINTERNAL
705 
706 ///////////////////////////////////////////////////////////////////////////////
707 // FIXME: the API function below belong into the namespace hpx::threads
708 namespace hpx { namespace applier
709 {
710     ///////////////////////////////////////////////////////////////////////////
711     /// \brief Create a new \a thread using the given function as the work to
712     ///        be executed.
713     ///
714     /// \param func       [in] The function to be executed as the thread-function.
715     ///                   This function has to expose the minimal low level
716     ///                   HPX-thread interface, i.e. it takes one argument (a
717     ///                   \a threads#thread_state_ex_enum) and returns a
718     ///                   \a threads#thread_state_enum.
719     /// \param description [in] A optional string describing the newly created
720     ///                   thread. This is useful for debugging and logging
721     ///                   purposes as this string will be inserted in the logs.
722     /// \param initial_state [in] The thread state the newly created thread
723     ///                   should have. If this is not given it defaults to
724     ///                   \a threads#pending, which means that the new thread
725     ///                   will be scheduled to run as soon as it is created.
726     /// \param run_now    [in] If this is set to `true` the thread object will
727     ///                   be actually immediately created. Otherwise the
728     ///                   thread-manager creates a work-item description, which
729     ///                   will result in creating a thread object later (if
730     ///                   no work is available any more). The default is to
731     ///                   immediately create the thread object.
732     /// \param priority   [in] This is the priority the newly created HPX-thread
733     ///                   should be executed with. The default is \a
734     ///                   threads#thread_priority_normal. This parameter is not
735     ///                   guaranteed to be taken into account as it depends on
736     ///                   the used scheduling policy whether priorities are
737     ///                   supported in the first place.
738     /// \param os_thread  [in] The number of the shepherd thread the newly
739     ///                   created HPX-thread should run on. If this is given it
740     ///                   will be no more than a hint in any case, mainly
741     ///                   because even if the HPX-thread gets scheduled on the
742     ///                   queue of the requested shepherd thread, it still can
743     ///                   be stolen by another shepherd thread. If this is not
744     ///                   given, the system will select a shepherd thread.
745     /// \param ec         [in,out] This represents the error status on exit,
746     ///                   if this is pre-initialized to \a hpx#throws
747     ///                   the function will throw on error instead.
748     ///
749     /// \returns This function will return the internal id of the newly created
750     ///          HPX-thread or threads#invalid_thread_id (if run_now is set to
751     ///          `false`).
752     ///
753     /// \note The value returned by the thread function will be interpreted by
754     ///       the thread manager as the new thread state the executed HPX-thread
755     ///       needs to be switched to. Normally, HPX-threads will either return
756     ///       \a threads#terminated (if the thread should be destroyed) or
757     ///       \a threads#suspended (if the thread needs to be suspended because
758     ///       it is waiting for an external event to happen). The external
759     ///       event will set the state of the thread back to pending, which
760     ///       will re-schedule the HPX-thread.
761     ///
762     /// \throws invalid_status if the runtime system has not been started yet.
763     ///
764     ///
765     /// \note             As long as \a ec is not pre-initialized to
766     ///                   \a hpx#throws this function doesn't
767     ///                   throw but returns the result code using the
768     ///                   parameter \a ec. Otherwise it throws an instance
769     ///                   of hpx#exception.
770     HPX_API_EXPORT threads::thread_id_type register_thread_plain(
771         threads::thread_function_type && func,
772         util::thread_description const& description = util::thread_description(),
773         threads::thread_state_enum initial_state = threads::pending,
774         bool run_now = true,
775         threads::thread_priority priority = threads::thread_priority_normal,
776         threads::thread_schedule_hint = threads::thread_schedule_hint(),
777         threads::thread_stacksize stacksize = threads::thread_stacksize_default,
778         error_code& ec = throws);
779 
780     ///////////////////////////////////////////////////////////////////////////
781     /// \brief Create a new \a thread using the given data.
782     ///
783     /// \note This function is completely equivalent to the first overload
784     ///       of threads#register_thread_plain above, except that part of the
785     ///       parameters are passed as members of the threads#thread_init_data
786     ///       object.
787     ///
788     HPX_API_EXPORT threads::thread_id_type register_thread_plain(
789         threads::thread_init_data& data,
790         threads::thread_state_enum initial_state = threads::pending,
791         bool run_now = true, error_code& ec = throws);
792 
793     ///////////////////////////////////////////////////////////////////////////
794     /// \brief Create a new \a thread using the given function as the work to
795     ///        be executed.
796     ///
797     /// \param func       [in] The function to be executed as the thread-function.
798     ///                   This function has to expose the minimal low level
799     ///                   HPX-thread interface, i.e. it takes one argument (a
800     ///                   \a threads#thread_state_ex_enum). The thread will be
801     ///                   terminated after the function returns.
802     ///
803     /// \note All other arguments are equivalent to those of the function
804     ///       \a threads#register_thread_plain
805     ///
806     namespace detail
807     {
808         template <typename F>
809         struct thread_function
810         {
811             F f;
812 
operator ()hpx::applier::detail::thread_function813             inline threads::thread_result_type operator()(threads::thread_arg_type)
814             {
815                 // execute the actual thread function
816                 f(threads::wait_signaled);
817 
818                 // Verify that there are no more registered locks for this
819                 // OS-thread. This will throw if there are still any locks
820                 // held.
821                 util::force_error_on_lock();
822 
823                 return threads::thread_result_type(threads::terminated,
824                     threads::invalid_thread_id);
825             }
826         };
827 
828         template <typename F>
829         struct thread_function_nullary
830         {
831             F f;
832 
operator ()hpx::applier::detail::thread_function_nullary833             inline threads::thread_result_type operator()(threads::thread_arg_type)
834             {
835                 // execute the actual thread function
836                 f();
837 
838                 // Verify that there are no more registered locks for this
839                 // OS-thread. This will throw if there are still any locks
840                 // held.
841                 util::force_error_on_lock();
842 
843                 return threads::thread_result_type(threads::terminated,
844                     threads::invalid_thread_id);
845             }
846         };
847     }
848 
849     template <typename F>
register_thread(F && func,util::thread_description const & description=util::thread_description (),threads::thread_state_enum initial_state=threads::pending,bool run_now=true,threads::thread_priority priority=threads::thread_priority_normal,threads::thread_schedule_hint os_thread=threads::thread_schedule_hint (),threads::thread_stacksize stacksize=threads::thread_stacksize_default,error_code & ec=throws)850     threads::thread_id_type register_thread(
851         F && func,
852         util::thread_description const& description = util::thread_description(),
853         threads::thread_state_enum initial_state = threads::pending,
854         bool run_now = true,
855         threads::thread_priority priority = threads::thread_priority_normal,
856         threads::thread_schedule_hint os_thread = threads::thread_schedule_hint(),
857         threads::thread_stacksize stacksize = threads::thread_stacksize_default,
858         error_code& ec = throws)
859     {
860         threads::thread_function_type thread_func(
861             detail::thread_function<typename std::decay<F>::type>{
862                 std::forward<F>(func)});
863         return register_thread_plain(std::move(thread_func),
864             description, initial_state, run_now, priority, os_thread, stacksize,
865             ec);
866     }
867 
868     ///////////////////////////////////////////////////////////////////////////
869     /// \brief Create a new \a thread using the given function as the work to
870     ///        be executed.
871     ///
872     /// \param func       [in] The function to be executed as the thread-function.
873     ///                   This function has to expose the minimal low level
874     ///                   HPX-thread interface, i.e. it takes no arguments. The
875     ///                   thread will be terminated after the function returns.
876     ///
877     /// \note All other arguments are equivalent to those of the function
878     ///       \a threads#register_thread_plain
879     ///
880     template <typename F>
register_thread_nullary(F && func,util::thread_description const & description=util::thread_description (),threads::thread_state_enum initial_state=threads::pending,bool run_now=true,threads::thread_priority priority=threads::thread_priority_normal,threads::thread_schedule_hint os_thread=threads::thread_schedule_hint (),threads::thread_stacksize stacksize=threads::thread_stacksize_default,error_code & ec=throws)881     threads::thread_id_type register_thread_nullary(
882         F && func,
883         util::thread_description const& description = util::thread_description(),
884         threads::thread_state_enum initial_state = threads::pending,
885         bool run_now = true,
886         threads::thread_priority priority = threads::thread_priority_normal,
887         threads::thread_schedule_hint os_thread = threads::thread_schedule_hint(),
888         threads::thread_stacksize stacksize = threads::thread_stacksize_default,
889         error_code& ec = throws)
890     {
891         threads::thread_function_type thread_func(
892             detail::thread_function_nullary<typename std::decay<F>::type>{
893                 std::forward<F>(func)});
894         return register_thread_plain(std::move(thread_func),
895             description, initial_state, run_now, priority, os_thread, stacksize,
896             ec);
897     }
898 
899     ///////////////////////////////////////////////////////////////////////////
900     /// \brief Create a new work item using the given function as the
901     ///        work to be executed. This work item will be used to create a
902     ///        \a threads#thread instance whenever the shepherd thread runs out
903     ///        of work only. The created work descriptions will be queued
904     ///        separately, causing them to be converted into actual thread
905     ///        objects on a first-come-first-served basis.
906     ///
907     /// \param func       [in] The function to be executed as the thread-function.
908     ///                   This function has to expose the minimal low level
909     ///                   HPX-thread interface, i.e. it takes one argument (a
910     ///                   \a threads#thread_state_ex_enum) and returns a
911     ///                   \a threads#thread_state_enum.
912     /// \param description [in] A optional string describing the newly created
913     ///                   thread. This is useful for debugging and logging
914     ///                   purposes as this string will be inserted in the logs.
915     /// \param initial_state [in] The thread state the newly created thread
916     ///                   should have. If this is not given it defaults to
917     ///                   \a threads#pending, which means that the new thread
918     ///                   will be scheduled to run as soon as it is created.
919     /// \param priority   [in] This is the priority the newly created HPX-thread
920     ///                   should be executed with. The default is \a
921     ///                   threads#thread_priority_normal. This parameter is not
922     ///                   guaranteed to be taken into account as it depends on
923     ///                   the used scheduling policy whether priorities are
924     ///                   supported in the first place.
925     /// \param os_thread  [in] The number of the shepherd thread the newly
926     ///                   created HPX-thread should run on. If this is given it
927     ///                   will be no more than a hint in any case, mainly
928     ///                   because even if the HPX-thread gets scheduled on the
929     ///                   queue of the requested shepherd thread, it still can
930     ///                   be stolen by another shepherd thread. If this is not
931     ///                   given, the system will select a shepherd thread.
932     /// \param ec         [in,out] This represents the error status on exit,
933     ///                   if this is pre-initialized to \a hpx#throws
934     ///                   the function will throw on error instead.
935     ///
936     /// \note The value returned by the thread function will be interpreted by
937     ///       the thread manager as the new thread state the executed HPX-thread
938     ///       needs to be switched to. Normally, HPX-threads will either return
939     ///       \a threads#terminated (if the thread should be destroyed) or
940     ///       \a threads#suspended (if the thread needs to be suspended because
941     ///       it is waiting for an external event to happen). The external
942     ///       event will set the state of the thread back to pending, which
943     ///       will re-schedule the HPX-thread.
944     ///
945     /// \throws invalid_status if the runtime system has not been started yet.
946     ///
947     HPX_API_EXPORT void register_work_plain(
948         threads::thread_function_type && func,
949         util::thread_description const& description = util::thread_description(),
950         std::uint64_t /*naming::address_type*/ lva = 0,
951         threads::thread_state_enum initial_state = threads::pending,
952         threads::thread_priority priority = threads::thread_priority_normal,
953         threads::thread_schedule_hint = threads::thread_schedule_hint(),
954         threads::thread_stacksize stacksize = threads::thread_stacksize_default,
955         error_code& ec = throws);
956 
957     ///////////////////////////////////////////////////////////////////////////
958     /// \brief Create a new work item using the given function as the
959     ///        work to be executed.
960     ///
961     /// \note This function is completely equivalent to the first overload
962     ///       of threads#register_work_plain above, except that part of the
963     ///       parameters are passed as members of the threads#thread_init_data
964     ///       object.
965     ///
966     HPX_API_EXPORT void register_work_plain(
967         threads::thread_init_data& data,
968         threads::thread_state_enum initial_state = threads::pending,
969         error_code& ec = throws);
970 
971     ///////////////////////////////////////////////////////////////////////////
972     /// \brief Create a new work item using the given function as the
973     ///        work to be executed.
974     ///
975     /// \param func       [in] The function to be executed as the thread-function.
976     ///                   This function has to expose the minimal low level
977     ///                   HPX-thread interface, i.e. it takes one argument (a
978     ///                   \a threads#thread_state_ex_enum). The thread will be
979     ///                   terminated after the function returns.
980     ///
981     /// \note All other arguments are equivalent to those of the function
982     ///       \a threads#register_work_plain
983     ///
984     template <typename F>
register_work(F && func,util::thread_description const & description=util::thread_description (),threads::thread_state_enum initial_state=threads::pending,threads::thread_priority priority=threads::thread_priority_normal,threads::thread_schedule_hint os_thread=threads::thread_schedule_hint (),threads::thread_stacksize stacksize=threads::thread_stacksize_default,error_code & ec=throws)985     void register_work(
986         F && func,
987         util::thread_description const& description = util::thread_description(),
988         threads::thread_state_enum initial_state = threads::pending,
989         threads::thread_priority priority = threads::thread_priority_normal,
990         threads::thread_schedule_hint os_thread = threads::thread_schedule_hint(),
991         threads::thread_stacksize stacksize = threads::thread_stacksize_default,
992         error_code& ec = throws)
993     {
994         threads::thread_function_type thread_func(
995             detail::thread_function<typename std::decay<F>::type>{
996                 std::forward<F>(func)});
997         return register_work_plain(std::move(thread_func),
998             description, 0, initial_state, priority, os_thread, stacksize,
999             ec);
1000     }
1001 
1002     ///////////////////////////////////////////////////////////////////////////
1003     /// \brief Create a new work item using the given function as the
1004     ///        work to be executed.
1005     ///
1006     /// \param func       [in] The function to be executed as the thread-function.
1007     ///                   This function has to expose the minimal low level
1008     ///                   HPX-thread interface, i.e. it takes no arguments. The
1009     ///                   thread will be terminated after the function returns.
1010     ///
1011     /// \note All other arguments are equivalent to those of the function
1012     ///       \a threads#register_work_plain
1013     ///
1014     template <typename F>
register_work_nullary(F && func,util::thread_description const & description=util::thread_description (),threads::thread_state_enum initial_state=threads::pending,threads::thread_priority priority=threads::thread_priority_normal,threads::thread_schedule_hint os_thread=threads::thread_schedule_hint (),threads::thread_stacksize stacksize=threads::thread_stacksize_default,error_code & ec=throws)1015     void register_work_nullary(
1016         F && func,
1017         util::thread_description const& description = util::thread_description(),
1018         threads::thread_state_enum initial_state = threads::pending,
1019         threads::thread_priority priority = threads::thread_priority_normal,
1020         threads::thread_schedule_hint os_thread = threads::thread_schedule_hint(),
1021         threads::thread_stacksize stacksize = threads::thread_stacksize_default,
1022         error_code& ec = throws)
1023     {
1024         threads::thread_function_type thread_func(
1025             detail::thread_function_nullary<typename std::decay<F>::type>{
1026                 std::forward<F>(func)});
1027         return register_work_plain(std::move(thread_func),
1028             description, 0, initial_state, priority, os_thread, stacksize,
1029             ec);
1030     }
1031 }}
1032 
1033 ///////////////////////////////////////////////////////////////////////////////
1034 namespace hpx { namespace threads
1035 {
1036     // Import all thread creation functions into this name space (we will
1037     // deprecate the functions in namespace applier above at some point).
1038     using applier::register_thread_plain;
1039     using applier::register_thread;
1040     using applier::register_thread_nullary;
1041 
1042     using applier::register_work_plain;
1043     using applier::register_work;
1044     using applier::register_work_nullary;
1045 }}
1046 
1047 /// \endcond
1048 
1049 #endif /*HPX_RUNTIME_THREADS_THREAD_HELPERS_HPP*/
1050