/home/users/khuck/src/hpx-lsu/src/runtime/threads/thread_helpers.cpp

Line% of fetchesSource
1  
//  Copyright (c) 2007-2016 Hartmut Kaiser
2  
//  Copyright (c)      2011 Bryce Lelbach
3  
//
4  
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
5  
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
7  
#include <hpx/runtime/threads/thread_helpers.hpp>
8  
9  
#include <hpx/error_code.hpp>
10  
#include <hpx/exception.hpp>
11  
#include <hpx/runtime.hpp>
12  
#include <hpx/state.hpp>
13  
#include <hpx/throw_exception.hpp>
14  
#include <hpx/runtime/threads/detail/set_thread_state.hpp>
15  
#include <hpx/runtime/threads/executors/current_executor.hpp>
16  
#include <hpx/runtime/threads/thread_data_fwd.hpp>
17  
#include <hpx/runtime/threads/thread_enums.hpp>
18  
#ifdef HPX_HAVE_THREAD_BACKTRACE_ON_SUSPENSION
19  
#include <hpx/util/backtrace.hpp>
20  
#endif
21  
#ifdef HPX_HAVE_VERIFY_LOCKS
22  
#  include <hpx/util/register_locks.hpp>
23  
#endif
24  
#include <hpx/util/steady_clock.hpp>
25  
#include <hpx/util/thread_description.hpp>
26  
#include <hpx/util/thread_specific_ptr.hpp>
27  
28  
#include <cstddef>
29  
#include <limits>
30  
#include <sstream>
31  
#include <string>
32  
#include <utility>
33  
34  
///////////////////////////////////////////////////////////////////////////////
35  
namespace hpx { namespace threads
36  
{
37  
    ///////////////////////////////////////////////////////////////////////////
38  
    thread_state set_thread_state(thread_id_type const& id, thread_state_enum state,
39  
        thread_state_ex_enum stateex, thread_priority priority, error_code& ec)
40  
    {
41  
        if (&ec != &throws)
42  
            ec = make_success_code();
43  
44  
        return  detail::set_thread_state(id, state, stateex,
45  
            priority, std::size_t(-1), ec);
46  
    }
47  
48  
    ///////////////////////////////////////////////////////////////////////////
49  
    thread_id_type set_thread_state(thread_id_type const& id,
50  
        util::steady_time_point const& abs_time, thread_state_enum state,
51  
        thread_state_ex_enum stateex, thread_priority priority, error_code& ec)
52  
    {
53  
        return detail::set_thread_state_timed(*id->get_scheduler_base(), abs_time, id,
54  
            state, stateex, priority, std::size_t(-1), ec);
55  
    }
56  
57  
    ///////////////////////////////////////////////////////////////////////////
58  
    thread_state get_thread_state(thread_id_type const& id, error_code& ec)
59  
    {
60  
        return id ? id->get_state() : thread_state(terminated, wait_unknown);
61  
    }
62  
63  
    ///////////////////////////////////////////////////////////////////////////
64  
    std::size_t get_thread_phase(thread_id_type const& id, error_code& ec)
65  
    {
66  
        return id ? id->get_thread_phase() : std::size_t(~0);;
67  
    }
68  
69  
    ///////////////////////////////////////////////////////////////////////////
70  
    threads::thread_priority get_thread_priority(thread_id_type const& id,
71  
        error_code& ec)
72  
    {
73  
        return id ? id->get_priority() : thread_priority_unknown;
74  
    }
75  
76  
    /// The get_stack_size function is part of the thread related API. It
77  
    std::ptrdiff_t get_stack_size(thread_id_type const& id, error_code& ec)
78  
    {
79  
        return id ? id->get_stack_size() :
80  
            static_cast<std::ptrdiff_t>(thread_stacksize_unknown);
81  
    }
82  
83  
    void interrupt_thread(thread_id_type const& id, bool flag, error_code& ec)
84  
    {
85  
        if (HPX_UNLIKELY(!id)) {
86  
            HPX_THROWS_IF(ec, null_thread_id,
87  
                "hpx::threads::interrupt_thread",
88  
                "null thread id encountered");
89  
            return;
90  
        }
91  
92  
        if (&ec != &throws)
93  
            ec = make_success_code();
94  
95  
        id->interrupt(flag);      // notify thread
96  
97  
        // set thread state to pending, if the thread is currently active,
98  
        // this will be rescheduled until it calls an interruption point
99  
        set_thread_state(id, pending, wait_abort,
100  
            thread_priority_normal, ec);
101  
    }
102  
103  
    void interruption_point(thread_id_type const& id, error_code& ec)
104  
    {
105  
        if (HPX_UNLIKELY(!id)) {
106  
            HPX_THROWS_IF(ec, null_thread_id,
107  
                "hpx::threads::interruption_point",
108  
                "null thread id encountered");
109  
            return;
110  
        }
111  
112  
        if (&ec != &throws)
113  
            ec = make_success_code();
114  
115  
        id->interruption_point();      // notify thread
116  
    }
117  
118  
    ///////////////////////////////////////////////////////////////////////////
119  
    bool get_thread_interruption_enabled(thread_id_type const& id,
120  
        error_code& ec)
121  
    {
122  
        if (HPX_UNLIKELY(!id)) {
123  
            HPX_THROW_EXCEPTION(null_thread_id,
124  
                "hpx::threads::get_thread_interruption_enabled",
125  
                "null thread id encountered");
126  
            return false;
127  
        }
128  
129  
        if (&ec != &throws)
130  
            ec = make_success_code();
131  
132  
        return id->interruption_enabled();
133  
    }
134  
135  
    bool set_thread_interruption_enabled(thread_id_type const& id, bool enable,
136  
        error_code& ec)
137  
    {
138  
        if (HPX_UNLIKELY(!id)) {
139  
            HPX_THROW_EXCEPTION(null_thread_id,
140  
                "hpx::threads::get_thread_interruption_enabled",
141  
                "null thread id encountered");
142  
            return false;
143  
        }
144  
145  
        if (&ec != &throws)
146  
            ec = make_success_code();
147  
148  
        return id->set_interruption_enabled(enable);
149  
    }
150  
151  
    bool get_thread_interruption_requested(thread_id_type const& id,
152  
        error_code& ec)
153  
    {
154  
        if (HPX_UNLIKELY(!id)) {
155  
            HPX_THROWS_IF(ec, null_thread_id,
156  
                "hpx::threads::get_thread_interruption_requested",
157  
                "null thread id encountered");
158  
            return false;
159  
        }
160  
161  
        if (&ec != &throws)
162  
            ec = make_success_code();
163  
164  
        return id->interruption_requested();
165  
    }
166  
167  
    ///////////////////////////////////////////////////////////////////////////
168  
    std::size_t get_thread_data(thread_id_type const& id, error_code& ec)
169  
    {
170  
        if (HPX_UNLIKELY(!id)) {
171  
            HPX_THROWS_IF(ec, null_thread_id,
172  
                "hpx::threads::get_thread_data",
173  
                "null thread id encountered");
174  
            return 0;
175  
        }
176  
177  
        return id->get_thread_data();
178  
    }
179  
180  
    std::size_t set_thread_data(thread_id_type const& id, std::size_t data,
181  
        error_code& ec)
182  
    {
183  
        if (HPX_UNLIKELY(!id)) {
184  
            HPX_THROWS_IF(ec, null_thread_id,
185  
                "hpx::threads::set_thread_data",
186  
                "null thread id encountered");
187  
            return 0;
188  
        }
189  
190  
        return id->set_thread_data(data);
191  
    }
192  
193  
    ////////////////////////////////////////////////////////////////////////////
194  
    struct continuation_recursion_count_tag {};
195  
    static util::thread_specific_ptr<
196  
            std::size_t, continuation_recursion_count_tag
197  
        > continuation_recursion_count;
198  
199  
    std::size_t& get_continuation_recursion_count()
200  
    {
201  
        thread_self* self_ptr = get_self_ptr();
202  
        if (self_ptr)
203  
            return self_ptr->get_continuation_recursion_count();
204  
205  
        if (nullptr == continuation_recursion_count.get())
206  
            continuation_recursion_count.reset(new std::size_t(0));
207  
208  
        return *continuation_recursion_count.get();
209  
    }
210  
211  
    void reset_continuation_recursion_count()
212  
    {
213  
        delete continuation_recursion_count.get();
214  
    }
215  
216  
    ///////////////////////////////////////////////////////////////////////////
217  
    void run_thread_exit_callbacks(thread_id_type const& id, error_code& ec)
218  
    {
219  
        if (HPX_UNLIKELY(!id)) {
220  
            HPX_THROWS_IF(ec, null_thread_id,
221  
                "hpx::threads::run_thread_exit_callbacks",
222  
                "null thread id encountered");
223  
            return;
224  
        }
225  
226  
        if (&ec != &throws)
227  
            ec = make_success_code();
228  
229  
        id->run_thread_exit_callbacks();
230  
    }
231  
232  
    bool add_thread_exit_callback(thread_id_type const& id,
233  
        util::function_nonser<void()> const& f, error_code& ec)
234  
    {
235  
        if (HPX_UNLIKELY(!id)) {
236  
            HPX_THROWS_IF(ec, null_thread_id,
237  
                "hpx::threads::add_thread_exit_callback",
238  
                "null thread id encountered");
239  
            return false;
240  
        }
241  
242  
        if (&ec != &throws)
243  
            ec = make_success_code();
244  
245  
        return id->add_thread_exit_callback(f);
246  
    }
247  
248  
    void free_thread_exit_callbacks(thread_id_type const& id, error_code& ec)
249  
    {
250  
        if (HPX_UNLIKELY(!id)) {
251  
            HPX_THROWS_IF(ec, null_thread_id,
252  
                "hpx::threads::add_thread_exit_callback",
253  
                "null thread id encountered");
254  
            return;
255  
        }
256  
257  
        if (&ec != &throws)
258  
            ec = make_success_code();
259  
260  
        id->free_thread_exit_callbacks();
261  
    }
262  
263  
    ///////////////////////////////////////////////////////////////////////////
264  
    /// The get_thread_description function is part of the thread related API and
265  
    /// allows to query the description of one of the thread id
266  
    util::thread_description get_thread_description(thread_id_type const& id,
267  
        error_code& ec)
268  
    {
269  
        return id ? id->get_description() : util::thread_description("<unknown>");
270  
    }
271  
272  
    util::thread_description set_thread_description(thread_id_type const& id,
273  
        util::thread_description const& desc, error_code& ec)
274  
    {
275  
        if (HPX_UNLIKELY(!id)) {
276  
            HPX_THROWS_IF(ec, null_thread_id,
277  
                "hpx::threads::set_thread_description",
278  
                "null thread id encountered");
279  
            return util::thread_description();
280  
        }
281  
        if (&ec != &throws)
282  
            ec = make_success_code();
283  
284  
        return id->set_description(desc);
285  
    }
286  
287  
    util::thread_description get_thread_lco_description(
288  
        thread_id_type const& id, error_code& ec)
289  
    {
290  
        if (HPX_UNLIKELY(!id)) {
291  
            HPX_THROWS_IF(ec, null_thread_id,
292  
                "hpx::threads::get_thread_lco_description",
293  
                "null thread id encountered");
294  
            return nullptr;
295  
        }
296  
297  
        if (&ec != &throws)
298  
            ec = make_success_code();
299  
300  
        return id ? id->get_lco_description() : "<unknown>";
301  
    }
302  
303  
    util::thread_description set_thread_lco_description(
304  
        thread_id_type const& id, util::thread_description const& desc,
305  
        error_code& ec)
306  
    {
307  
        if (HPX_UNLIKELY(!id)) {
308  
            HPX_THROWS_IF(ec, null_thread_id,
309  
                "hpx::threads::set_thread_lco_description",
310  
                "null thread id encountered");
311  
            return nullptr;
312  
        }
313  
314  
        if (&ec != &throws)
315  
            ec = make_success_code();
316  
317  
        if (id)
318  
            return id->set_lco_description(desc);
319  
        return nullptr;
320  
    }
321  
322  
    ///////////////////////////////////////////////////////////////////////////
323  
#ifdef HPX_HAVE_THREAD_FULLBACKTRACE_ON_SUSPENSION
324  
    char const* get_thread_backtrace(thread_id_type const& id, error_code& ec)
325  
#else
326  
    util::backtrace const* get_thread_backtrace(thread_id_type const& id,
327  
        error_code& ec)
328  
#endif
329  
    {
330  
        if (HPX_UNLIKELY(!id)) {
331  
            HPX_THROWS_IF(ec, null_thread_id,
332  
                "hpx::threads::get_thread_backtrace",
333  
                "null thread id encountered");
334  
            return nullptr;
335  
        }
336  
337  
        if (&ec != &throws)
338  
            ec = make_success_code();
339  
340  
        return id ? id->get_backtrace() : nullptr;
341  
    }
342  
343  
#ifdef HPX_HAVE_THREAD_FULLBACKTRACE_ON_SUSPENSION
344  
    char const* set_thread_backtrace(thread_id_type const& id,
345  
        char const* bt, error_code& ec)
346  
#else
347  
    util::backtrace const* set_thread_backtrace(thread_id_type const& id,
348  
        util::backtrace const* bt, error_code& ec)
349  
#endif
350  
    {
351  
        if (HPX_UNLIKELY(!id)) {
352  
            HPX_THROWS_IF(ec, null_thread_id,
353  
                "hpx::threads::set_thread_backtrace",
354  
                "null thread id encountered");
355  
            return nullptr;
356  
        }
357  
358  
        if (&ec != &throws)
359  
            ec = make_success_code();
360  
361  
        return id ? id->set_backtrace(bt) : nullptr;
362  
    }
363  
364  
    threads::executors::current_executor
365  
        get_executor(thread_id_type const& id, error_code& ec)
366  
    {
367  
        if (HPX_UNLIKELY(!id)) {
368  
            HPX_THROWS_IF(ec, null_thread_id,
369  
                "hpx::threads::get_executor",
370  
                "null thread id encountered");
371  
            return executors::current_executor(nullptr);
372  
        }
373  
374  
        if (&ec != &throws)
375  
            ec = make_success_code();
376  
377  
        return executors::current_executor(id->get_scheduler_base());
378  
    }
379  
}}
380  
381  
namespace hpx { namespace this_thread
382  
{
383  
    namespace detail
384  
    {
385  
        struct reset_lco_description
386  
        {
387  
            reset_lco_description(threads::thread_id_type const& id,
388  
                    util::thread_description const& description,
389  
                    error_code& ec)
390  
              : id_(id), ec_(ec)
391  
            {
392  
                old_desc_ = threads::set_thread_lco_description(id_,
393  
                    description, ec_);
394  
            }
395  
396  
            ~reset_lco_description()
397  
            {
398  
                threads::set_thread_lco_description(id_, old_desc_, ec_);
399  
            }
400  
401  
            threads::thread_id_type id_;
402  
            util::thread_description old_desc_;
403  
            error_code& ec_;
404  
        };
405  
406  
#ifdef HPX_HAVE_THREAD_BACKTRACE_ON_SUSPENSION
407  
        struct reset_backtrace
408  
        {
409  
            reset_backtrace(threads::thread_id_type const& id, error_code& ec)
410  
              : id_(id),
411  
                backtrace_(new hpx::util::backtrace()),
412  
#ifdef HPX_HAVE_THREAD_FULLBACKTRACE_ON_SUSPENSION
413  
                full_backtrace_(backtrace_->trace()),
414  
#endif
415  
                ec_(ec)
416  
            {
417  
#ifdef HPX_HAVE_THREAD_FULLBACKTRACE_ON_SUSPENSION
418  
                threads::set_thread_backtrace(id_, full_backtrace_.c_str(), ec_);
419  
#else
420  
                threads::set_thread_backtrace(id_, backtrace_.get(), ec_);
421  
#endif
422  
            }
423  
            ~reset_backtrace()
424  
            {
425  
                threads::set_thread_backtrace(id_, 0, ec_);
426  
            }
427  
428  
            threads::thread_id_type id_;
429  
            boost::scoped_ptr<hpx::util::backtrace> backtrace_;
430  
#ifdef HPX_HAVE_THREAD_FULLBACKTRACE_ON_SUSPENSION
431  
            std::string full_backtrace_;
432  
#endif
433  
            error_code& ec_;
434  
        };
435  
#endif
436  
    }
437  
438  
    /// The function \a suspend will return control to the thread manager
439  
    /// (suspends the current thread). It sets the new state of this thread
440  
    /// to the thread state passed as the parameter.
441  
    ///
442  
    /// If the suspension was aborted, this function will throw a
443  
    /// \a yield_aborted exception.
444  
    threads::thread_state_ex_enum suspend(
445  
        threads::thread_state_enum state,
446  
        threads::thread_id_type const& nextid,
447  
        util::thread_description const& description, error_code& ec)
448  
    {
449  
        // let the thread manager do other things while waiting
450  
        threads::thread_self& self = threads::get_self();
451  
        threads::thread_id_type id = threads::get_self_id();
452  
453  
        // handle interruption, if needed
454  
        threads::interruption_point(id, ec);
455  
        if (ec) return threads::wait_unknown;
456  
457  
        threads::thread_state_ex_enum statex = threads::wait_unknown;
458  
459  
        {
460  
            // verify that there are no more registered locks for this OS-thread
461  
#ifdef HPX_HAVE_VERIFY_LOCKS
462  
            util::verify_no_locks();
463  
#endif
464  
#ifdef HPX_HAVE_THREAD_DESCRIPTION
465  
            detail::reset_lco_description desc(id, description, ec);
466  
#endif
467  
#ifdef HPX_HAVE_THREAD_BACKTRACE_ON_SUSPENSION
468  
            detail::reset_backtrace bt(id, ec);
469  
#endif
470  
471  
            // suspend the HPX-thread
472  
            statex = self.yield(threads::thread_result_type(state, nextid));
473  
        }
474  
475  
        // handle interruption, if needed
476  
        threads::interruption_point(id, ec);
477  
        if (ec) return threads::wait_unknown;
478  
479  
        // handle interrupt and abort
480  
        if (statex == threads::wait_abort)
481  
        {
482  
            std::ostringstream strm;
483  
            strm << "thread(" << threads::get_self_id() << ", "
484  
                  << threads::get_thread_description(id)
485  
                  << ") aborted (yield returned wait_abort)";
486  
            HPX_THROWS_IF(ec, yield_aborted, "suspend",
487  
                strm.str());
488  
        }
489  
490  
        if (&ec != &throws)
491  
            ec = make_success_code();
492  
493  
        return statex;
494  
    }
495  
496  
    threads::thread_state_ex_enum suspend(
497  
        util::steady_time_point const& abs_time,
498  
        threads::thread_id_type const& nextid,
499  
        util::thread_description const& description, error_code& ec)
500  
    {
501  
        // schedule a thread waking us up at_time
502  
        threads::thread_self& self = threads::get_self();
503  
        threads::thread_id_type id = threads::get_self_id();
504  
505  
        // handle interruption, if needed
506  
        threads::interruption_point(id, ec);
507  
        if (ec) return threads::wait_unknown;
508  
509  
        // let the thread manager do other things while waiting
510  
        threads::thread_state_ex_enum statex = threads::wait_unknown;
511  
512  
        {
513  
#ifdef HPX_HAVE_VERIFY_LOCKS
514  
            // verify that there are no more registered locks for this OS-thread
515  
            util::verify_no_locks();
516  
#endif
517  
#ifdef HPX_HAVE_THREAD_DESCRIPTION
518  
            detail::reset_lco_description desc(id, description, ec);
519  
#endif
520  
#ifdef HPX_HAVE_THREAD_BACKTRACE_ON_SUSPENSION
521  
            detail::reset_backtrace bt(id, ec);
522  
#endif
523  
            threads::thread_id_type timer_id = threads::set_thread_state(id,
524  
                abs_time, threads::pending, threads::wait_timeout,
525  
                threads::thread_priority_boost, ec);
526  
            if (ec) return threads::wait_unknown;
527  
528  
            // suspend the HPX-thread
529  
            statex = self.yield(
530  
                threads::thread_result_type(threads::suspended, nextid));
531  
532  
            if (statex != threads::wait_timeout)
533  
            {
534  
                error_code ec1(lightweight);    // do not throw
535  
                threads::set_thread_state(timer_id,
536  
                    threads::pending, threads::wait_abort,
537  
                    threads::thread_priority_boost, ec1);
538  
            }
539  
        }
540  
541  
        // handle interruption, if needed
542  
        threads::interruption_point(id, ec);
543  
        if (ec) return threads::wait_unknown;
544  
545  
        // handle interrupt and abort
546  
        if (statex == threads::wait_abort) {
547  
            std::ostringstream strm;
548  
            strm << "thread(" << threads::get_self_id() << ", "
549  
                  << threads::get_thread_description(id)
550  
                  << ") aborted (yield returned wait_abort)";
551  
            HPX_THROWS_IF(ec, yield_aborted, "suspend_at",
552  
                strm.str());
553  
        }
554  
555  
        if (&ec != &throws)
556  
            ec = make_success_code();
557  
558  
        return statex;
559  
    }
560  
561  
    ///////////////////////////////////////////////////////////////////////////
562  
    threads::executors::current_executor get_executor(error_code& ec)
563  
    {
564  
        return threads::get_executor(threads::get_self_id(), ec);
565  
    }
566  
567  
    std::ptrdiff_t get_available_stack_space()
568  
    {
569  
        threads::thread_self *self = threads::get_self_ptr();
570  
        if(self)
571  
        {
572  
            return self->get_available_stack_space();
573  
        }
574  
575  
        return (std::numeric_limits<std::ptrdiff_t>::max)();
576  
    }
577  
578  
    bool has_sufficient_stack_space(std::size_t space_needed)
579  
    {
580  
        if (nullptr == hpx::threads::get_self_ptr())
581  
            return false;
582  
583  
#if defined(HPX_HAVE_THREADS_GET_STACK_POINTER)
584  
        std::ptrdiff_t remaining_stack = get_available_stack_space();
585  
        if (remaining_stack < 0)
586  
        {
587  
            HPX_THROW_EXCEPTION(out_of_memory,
588  
                "has_sufficient_stack_space", "Stack overflow");
589  
        }
590  
        bool sufficient_stack_space = std::size_t(remaining_stack) >= space_needed;
591  
592  
        // We might find ourselves in the situation where we don't have enough
593  
        // stack space, but can't really schedule a new thread. In this sitation,
594  
        // it would be best to change the code that provoked this behaviour
595  
        // instead of dynamically schedule a new thread. A such, we throw an
596  
        // exception to point to that problem instead of silently hanging because
597  
        // the thread will never be executed.
598  
        if (!sufficient_stack_space &&
599  
            !hpx::threads::threadmanager_is(hpx::state::state_running))
600  
        {
601  
            HPX_THROW_EXCEPTION(invalid_status,
602  
                "has_sufficient_stack_space",
603  
                "A potential stack overflow has been detected. Unable to "
604  
                "schedule new thread during startup/shutdown.");
605  
        }
606  
        return sufficient_stack_space;
607  
#else
608  
        return true;
609  
#endif
610  
    }
611  
}}
612  

Copyright (c) 2006-2012 Rogue Wave Software, Inc. All Rights Reserved.
Patents pending.