• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

STEllAR-GROUP / hpx / #857

28 Dec 2022 11:12PM UTC coverage: 86.543% (-0.06%) from 86.602%
#857

push

StellarBot
Merge #6118

6118: Modernize modules from level 17, 18, 19, and 20 r=hkaiser a=hkaiser

working towards https://github.com/STEllAR-GROUP/hpx/issues/5497

Modules:
- core/threading_base
- full/command_line_handling
- core/io_service
- core/schedulers
- core/synchronization
- core/futures
- core/thread_pools
- core/lcos_local
- core/pack_traversal
- core/resource_partitioner
- core/threading
- full/naming_base


Co-authored-by: Hartmut Kaiser <hartmut.kaiser@gmail.com>

849 of 849 new or added lines in 98 files covered. (100.0%)

174389 of 201505 relevant lines covered (86.54%)

1916353.25 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.98
/libs/core/threading_base/include/hpx/threading_base/thread_data.hpp
1
//  Copyright (c) 2007-2021 Hartmut Kaiser
2
//  Copyright (c)      2011 Bryce Lelbach
3
//  Copyright (c) 2008-2009 Chirag Dekate, Anshul Tandon
4
//
5
//  SPDX-License-Identifier: BSL-1.0
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
#pragma once
10

11
#include <hpx/config.hpp>
12
#include <hpx/assert.hpp>
13
#include <hpx/concurrency/spinlock_pool.hpp>
14
#include <hpx/coroutines/coroutine.hpp>
15
#include <hpx/coroutines/detail/combined_tagged_state.hpp>
16
#include <hpx/coroutines/thread_id_type.hpp>
17
#include <hpx/debugging/backtrace.hpp>
18
#include <hpx/execution_base/this_thread.hpp>
19
#include <hpx/functional/function.hpp>
20
#include <hpx/modules/errors.hpp>
21
#include <hpx/modules/logging.hpp>
22
#include <hpx/modules/memory.hpp>
23
#include <hpx/thread_support/atomic_count.hpp>
24
#include <hpx/threading_base/thread_description.hpp>
25
#include <hpx/threading_base/thread_init_data.hpp>
26
#if defined(HPX_HAVE_APEX)
27
#include <hpx/threading_base/external_timer.hpp>
28
#endif
29

30
#include <atomic>
31
#include <cstddef>
32
#include <cstdint>
33
#include <forward_list>
34
#include <memory>
35
#include <mutex>
36
#include <stack>
37
#include <string>
38
#include <utility>
39

40
#include <hpx/config/warnings_prefix.hpp>
41

42
////////////////////////////////////////////////////////////////////////////////
43
namespace hpx { namespace threads {
44

45
    namespace detail {
46
        using get_locality_id_type = std::uint32_t(hpx::error_code&);
47
        HPX_CORE_EXPORT void set_get_locality_id(get_locality_id_type* f);
48
        HPX_CORE_EXPORT std::uint32_t get_locality_id(hpx::error_code&);
49
    }    // namespace detail
50

51
    ////////////////////////////////////////////////////////////////////////////
52
    class HPX_CORE_EXPORT thread_data;    // forward declaration only
53

54
    ////////////////////////////////////////////////////////////////////////////
55
    /// The function \a get_self_id_data returns the data of the HPX thread id
56
    /// associated with the current thread (or nullptr if the current thread is
57
    /// not a HPX thread).
58
    HPX_CORE_EXPORT thread_data* get_self_id_data() noexcept;
59

60
    ////////////////////////////////////////////////////////////////////////////
61
    /// A \a thread is the representation of a ParalleX thread. It's a first
62
    /// class object in ParalleX. In our implementation this is a user level
63
    /// thread running on top of one of the OS threads spawned by the \a
64
    /// thread-manager.
65
    ///
66
    /// A \a thread encapsulates:
67
    ///  - A thread status word (see the functions \a thread#get_state and
68
    ///    \a thread#set_state)
69
    ///  - A function to execute (the thread function)
70
    ///  - A frame (in this implementation this is a block of memory used as
71
    ///    the threads stack)
72
    ///  - A block of registers (not implemented yet)
73
    ///
74
    /// Generally, \a threads are not created or executed directly. All
75
    /// functionality related to the management of \a threads is
76
    /// implemented by the thread-manager.
77
    class thread_data : public detail::thread_data_reference_counting
78
    {
79
    public:
80
        thread_data(thread_data const&) = delete;
81
        thread_data(thread_data&&) = delete;
82
        thread_data& operator=(thread_data const&) = delete;
83
        thread_data& operator=(thread_data&&) = delete;
84

85
    public:
86
        using spinlock_pool = util::spinlock_pool<thread_data>;
87

88
        /// The get_state function queries the state of this thread instance.
89
        ///
90
        /// \returns        This function returns the current state of this
91
        ///                 thread. It will return one of the values as defined
92
        ///                 by the \a thread_state enumeration.
93
        ///
94
        /// \note           This function will be seldom used directly. Most of
95
        ///                 the time the state of a thread will be retrieved
96
        ///                 by using the function \a threadmanager#get_state.
97
        thread_state get_state(
310,237,276✔
98
            std::memory_order order = std::memory_order_acquire) const noexcept
99
        {
100
            return current_state_.load(order);
310,294,999✔
101
        }
102

103
        /// The set_state function changes the state of this thread instance.
104
        ///
105
        /// \param newstate [in] The new state to be set for the thread.
106
        ///
107
        /// \note           This function will be seldom used directly. Most of
108
        ///                 the time the state of a thread will have to be
109
        ///                 changed using the threadmanager. Moreover,
110
        ///                 changing the thread state using this function does
111
        ///                 not change its scheduling status. It only sets the
112
        ///                 thread's status word. To change the thread's
113
        ///                 scheduling status \a threadmanager#set_state should
114
        ///                 be used.
115
        thread_state set_state(thread_schedule_state state,
470,006✔
116
            thread_restart_state state_ex = thread_restart_state::unknown,
117
            std::memory_order load_order = std::memory_order_acquire,
118
            std::memory_order exchange_order =
119
                std::memory_order_seq_cst) noexcept
120
        {
121
            thread_state prev_state = current_state_.load(load_order);
470,001✔
122

123
            for (;;)
470,006✔
124
            {
125
                thread_state tmp = prev_state;
469,997✔
126

127
                // ABA prevention for state only (not for state_ex)
128
                std::int64_t tag = tmp.tag();
469,997✔
129
                if (state != tmp.state())
469,997✔
130
                    ++tag;
469,996✔
131

132
                if (state_ex == thread_restart_state::unknown)
469,996✔
133
                    state_ex = tmp.state_ex();
469,994✔
134

135
                if (HPX_LIKELY(current_state_.compare_exchange_strong(tmp,
470,013✔
136
                        thread_state(state, state_ex, tag), exchange_order)))
137
                {
138
                    return prev_state;
470,013✔
139
                }
140

141
                prev_state = tmp;
×
142
            }
143
        }
144

145
        bool set_state_tagged(thread_schedule_state newstate,
83,320,326✔
146
            thread_state& prev_state, thread_state& new_tagged_state,
147
            std::memory_order exchange_order =
148
                std::memory_order_seq_cst) noexcept
149
        {
150
            new_tagged_state = thread_state(
83,322,164✔
151
                newstate, prev_state.state_ex(), prev_state.tag() + 1);
83,322,164✔
152

153
            thread_state tmp = prev_state;
83,322,164✔
154
            return current_state_.compare_exchange_strong(
166,640,652✔
155
                tmp, new_tagged_state, exchange_order);
83,322,164✔
156
        }
157

158
        /// The restore_state function changes the state of this thread
159
        /// instance depending on its current state. It will change the state
160
        /// atomically only if the current state is still the same as passed
161
        /// as the second parameter. Otherwise it won't touch the thread state
162
        /// of this instance.
163
        ///
164
        /// \param newstate [in] The new state to be set for the thread.
165
        /// \param oldstate [in] The old state of the thread which still has to
166
        ///                 be the current state.
167
        ///
168
        /// \note           This function will be seldom used directly. Most of
169
        ///                 the time the state of a thread will have to be
170
        ///                 changed using the threadmanager. Moreover,
171
        ///                 changing the thread state using this function does
172
        ///                 not change its scheduling status. It only sets the
173
        ///                 thread's status word. To change the thread's
174
        ///                 scheduling status \a threadmanager#set_state should
175
        ///                 be used.
176
        ///
177
        /// \returns This function returns \a true if the state has been
178
        ///          changed successfully
179
        bool restore_state(thread_state new_state, thread_state old_state,
83,500,845✔
180
            std::memory_order load_order = std::memory_order_relaxed,
181
            std::memory_order load_exchange =
182
                std::memory_order_seq_cst) noexcept
183
        {
184
            // ignore the state_ex while compare-exchanging
185
            thread_state current_state = current_state_.load(load_order);
83,387,315✔
186
            thread_restart_state state_ex = current_state.state_ex();
83,387,315✔
187

188
            // ABA prevention for state only (not for state_ex)
189
            std::int64_t tag = current_state.tag();
83,387,315✔
190
            if (new_state.state() != old_state.state())
83,387,315✔
191
                ++tag;
83,411,597✔
192

193
            thread_state old_tmp(old_state.state(), state_ex, old_state.tag());
83,414,460✔
194
            thread_state new_tmp(new_state.state(), state_ex, tag);
83,414,460✔
195

196
            return current_state_.compare_exchange_strong(
166,823,194✔
197
                old_tmp, new_tmp, load_exchange);
83,414,460✔
198
        }
199

200
        bool restore_state(thread_schedule_state new_state,
1,152,246✔
201
            thread_restart_state state_ex, thread_state old_state,
202
            std::memory_order load_exchange =
203
                std::memory_order_seq_cst) noexcept
204
        {
205
            // ABA prevention for state only (not for state_ex)
206
            std::int64_t tag = old_state.tag();
1,152,246✔
207
            if (new_state != old_state.state())
1,152,246✔
208
                ++tag;
1,152,246✔
209

210
            return current_state_.compare_exchange_strong(old_state,
2,304,492✔
211
                thread_state(new_state, state_ex, tag), load_exchange);
1,152,246✔
212
        }
213

214
    protected:
215
        /// The set_state function changes the extended state of this
216
        /// thread instance.
217
        ///
218
        /// \param newstate [in] The new extended state to be set for the
219
        ///                 thread.
220
        ///
221
        /// \note           This function will be seldom used directly. Most of
222
        ///                 the time the state of a thread will have to be
223
        ///                 changed using the threadmanager.
224
        thread_restart_state set_state_ex(
83,493,005✔
225
            thread_restart_state new_state) noexcept
226
        {
227
            thread_state prev_state =
228
                current_state_.load(std::memory_order_acquire);
83,491,101✔
229

230
            for (;;)
83,493,005✔
231
            {
232
                thread_state tmp = prev_state;
84,070,670✔
233

234
                if (HPX_LIKELY(current_state_.compare_exchange_strong(
84,070,670✔
235
                        tmp, thread_state(tmp.state(), new_state, tmp.tag()))))
236
                {
237
                    return prev_state.state_ex();
84,067,449✔
238
                }
239

240
                prev_state = tmp;
×
241
            }
242
        }
243

244
    public:
245
        /// Return the id of the component this thread is running in
246
        constexpr std::uint64_t    // same as naming::address_type
247
        get_component_id() const noexcept
248
        {
249
            return 0;
250
        }
251

252
#if !defined(HPX_HAVE_THREAD_DESCRIPTION)
253
        threads::thread_description get_description() const
39,568,653✔
254
        {
255
            return threads::thread_description("<unknown>");
39,568,188✔
256
        }
257
        threads::thread_description set_description(
1,685✔
258
            threads::thread_description /*value*/)
259
        {
260
            return threads::thread_description("<unknown>");
1,685✔
261
        }
262

263
        threads::thread_description get_lco_description() const
×
264
        {
265
            return threads::thread_description("<unknown>");
×
266
        }
267
        threads::thread_description set_lco_description(
×
268
            threads::thread_description /*value*/)
269
        {
270
            return threads::thread_description("<unknown>");
×
271
        }
272
#else
273
        threads::thread_description get_description() const
274
        {
275
            std::lock_guard<hpx::util::detail::spinlock> l(
276
                spinlock_pool::spinlock_for(this));
277
            return description_;
278
        }
279
        threads::thread_description set_description(
280
            threads::thread_description value)
281
        {
282
            std::lock_guard<hpx::util::detail::spinlock> l(
283
                spinlock_pool::spinlock_for(this));
284
            std::swap(description_, value);
285
            return value;
286
        }
287

288
        threads::thread_description get_lco_description() const
289
        {
290
            std::lock_guard<hpx::util::detail::spinlock> l(
291
                spinlock_pool::spinlock_for(this));
292
            return lco_description_;
293
        }
294
        threads::thread_description set_lco_description(
295
            threads::thread_description value)
296
        {
297
            std::lock_guard<hpx::util::detail::spinlock> l(
298
                spinlock_pool::spinlock_for(this));
299
            std::swap(lco_description_, value);
300
            return value;
301
        }
302
#endif
303

304
#if !defined(HPX_HAVE_THREAD_PARENT_REFERENCE)
305
        /// Return the locality of the parent thread
306
        constexpr std::uint32_t get_parent_locality_id() const noexcept
307
        {
308
            // this is the same as naming::invalid_locality_id
309
            return ~static_cast<std::uint32_t>(0);
310
        }
311

312
        /// Return the thread id of the parent thread
313
        constexpr thread_id_type get_parent_thread_id() const noexcept
314
        {
315
            return threads::invalid_thread_id;
316
        }
317

318
        /// Return the phase of the parent thread
319
        constexpr std::size_t get_parent_thread_phase() const noexcept
320
        {
321
            return 0;
322
        }
323
#else
324
        /// Return the locality of the parent thread
325
        std::uint32_t get_parent_locality_id() const noexcept
326
        {
327
            return parent_locality_id_;
328
        }
329

330
        /// Return the thread id of the parent thread
331
        thread_id_type get_parent_thread_id() const noexcept
332
        {
333
            return parent_thread_id_;
334
        }
335

336
        /// Return the phase of the parent thread
337
        std::size_t get_parent_thread_phase() const noexcept
338
        {
339
            return parent_thread_phase_;
340
        }
341
#endif
342

343
#ifdef HPX_HAVE_THREAD_MINIMAL_DEADLOCK_DETECTION
344
        void set_marked_state(thread_schedule_state mark) const noexcept
345
        {
346
            marked_state_ = mark;
347
        }
348
        thread_schedule_state get_marked_state() const noexcept
349
        {
350
            return marked_state_;
351
        }
352
#endif
353

354
#if !defined(HPX_HAVE_THREAD_BACKTRACE_ON_SUSPENSION)
355

356
#ifdef HPX_HAVE_THREAD_FULLBACKTRACE_ON_SUSPENSION
357
        constexpr char const* get_backtrace() const noexcept
358
        {
359
            return nullptr;
360
        }
361
        char const* set_backtrace(char const*) noexcept
362
        {
363
            return nullptr;
364
        }
365
#else
366
        constexpr util::backtrace const* get_backtrace() const noexcept
×
367
        {
368
            return nullptr;
×
369
        }
370
        util::backtrace const* set_backtrace(util::backtrace const*) noexcept
×
371
        {
372
            return nullptr;
×
373
        }
374
#endif
375

376
#else    // defined(HPX_HAVE_THREAD_BACKTRACE_ON_SUSPENSION
377

378
#ifdef HPX_HAVE_THREAD_FULLBACKTRACE_ON_SUSPENSION
379
        char const* get_backtrace() const noexcept
380
        {
381
            std::lock_guard<hpx::util::detail::spinlock> l(
382
                spinlock_pool::spinlock_for(this));
383
            return backtrace_;
384
        }
385
        char const* set_backtrace(char const* value) noexcept
386
        {
387
            std::lock_guard<hpx::util::detail::spinlock> l(
388
                spinlock_pool::spinlock_for(this));
389

390
            char const* bt = backtrace_;
391
            backtrace_ = value;
392
            return bt;
393
        }
394
#else
395
        util::backtrace const* get_backtrace() const noexcept
396
        {
397
            std::lock_guard<hpx::util::detail::spinlock> l(
398
                spinlock_pool::spinlock_for(this));
399
            return backtrace_;
400
        }
401
        util::backtrace const* set_backtrace(
402
            util::backtrace const* value) noexcept
403
        {
404
            std::lock_guard<hpx::util::detail::spinlock> l(
405
                spinlock_pool::spinlock_for(this));
406

407
            util::backtrace const* bt = backtrace_;
408
            backtrace_ = value;
409
            return bt;
410
        }
411
#endif
412

413
        // Generate full backtrace for captured stack
414
        std::string backtrace()
415
        {
416
            std::lock_guard<hpx::util::detail::spinlock> l(
417
                spinlock_pool::spinlock_for(this));
418

419
            std::string bt;
420
            if (0 != backtrace_)
421
            {
422
#ifdef HPX_HAVE_THREAD_FULLBACKTRACE_ON_SUSPENSION
423
                bt = *backtrace_;
424
#else
425
                bt = backtrace_->trace();
426
#endif
427
            }
428
            return bt;
429
        }
430
#endif
431

432
        constexpr thread_priority get_priority() const noexcept
4,594,588✔
433
        {
434
            return priority_;
4,594,589✔
435
        }
436
        void set_priority(thread_priority priority) noexcept
437
        {
438
            priority_ = priority;
439
        }
440

441
        // handle thread interruption
442
        bool interruption_requested() const noexcept
×
443
        {
444
            std::lock_guard<hpx::util::detail::spinlock> l(
×
445
                spinlock_pool::spinlock_for(this));
×
446
            return requested_interrupt_;
×
447
        }
×
448

449
        bool interruption_enabled() const noexcept
1✔
450
        {
451
            std::lock_guard<hpx::util::detail::spinlock> l(
1✔
452
                spinlock_pool::spinlock_for(this));
1✔
453
            return enabled_interrupt_;
1✔
454
        }
1✔
455

456
        bool set_interruption_enabled(bool enable) noexcept
2✔
457
        {
458
            std::lock_guard<hpx::util::detail::spinlock> l(
2✔
459
                spinlock_pool::spinlock_for(this));
2✔
460
            std::swap(enabled_interrupt_, enable);
2✔
461
            return enable;
2✔
462
        }
2✔
463

464
        void interrupt(bool flag = true)
6✔
465
        {
466
            std::unique_lock<hpx::util::detail::spinlock> l(
6✔
467
                spinlock_pool::spinlock_for(this));
6✔
468
            if (flag && !enabled_interrupt_)
6✔
469
            {
470
                l.unlock();
1✔
471
                HPX_THROW_EXCEPTION(hpx::error::thread_not_interruptable,
1✔
472
                    "thread_data::interrupt",
473
                    "interrupts are disabled for this thread");
474
                return;
475
            }
476
            requested_interrupt_ = flag;
5✔
477
        }
7✔
478

479
        bool interruption_point(bool throw_on_interrupt = true);
480

481
        bool add_thread_exit_callback(function<void()> const& f);
482
        void run_thread_exit_callbacks();
483
        void free_thread_exit_callbacks();
484

485
        HPX_FORCEINLINE constexpr bool is_stackless() const noexcept
83,544,859✔
486
        {
487
            return is_stackless_;
83,545,911✔
488
        }
489

490
        void destroy_thread() override;
491

492
        constexpr policies::scheduler_base* get_scheduler_base() const noexcept
26,157,917✔
493
        {
494
            return scheduler_base_;
26,157,882✔
495
        }
496

497
        constexpr std::size_t get_last_worker_thread_num() const noexcept
498
        {
499
            return last_worker_thread_num_;
500
        }
501

502
        void set_last_worker_thread_num(
76,033,873✔
503
            std::size_t last_worker_thread_num) noexcept
504
        {
505
            last_worker_thread_num_ = last_worker_thread_num;
76,034,555✔
506
        }
76,034,555✔
507

508
        constexpr std::ptrdiff_t get_stack_size() const noexcept
12,872,525✔
509
        {
510
            return stacksize_;
12,872,323✔
511
        }
512

513
        thread_stacksize get_stack_size_enum() const noexcept
506✔
514
        {
515
            return stacksize_enum_;
506✔
516
        }
517

518
        template <typename ThreadQueue>
519
        constexpr ThreadQueue& get_queue() noexcept
12,322,840✔
520
        {
521
            return *static_cast<ThreadQueue*>(queue_);
12,322,801✔
522
        }
523

524
        /// \brief Execute the thread function
525
        ///
526
        /// \returns        This function returns the thread state the thread
527
        ///                 should be scheduled from this point on. The thread
528
        ///                 manager will use the returned value to set the
529
        ///                 thread's scheduling status.
530
        inline coroutine_type::result_type operator()(
531
            hpx::execution_base::this_thread::detail::agent_storage*
532
                agent_storage);
533

534
        virtual thread_id_type get_thread_id() const
1,606,815✔
535
        {
536
            return thread_id_type{const_cast<thread_data*>(this)};
1,606,814✔
537
        }
538

539
#if !defined(HPX_HAVE_THREAD_PHASE_INFORMATION)
540
        virtual std::size_t get_thread_phase() const noexcept
11,611,581✔
541
        {
542
            return 0;
11,611,666✔
543
        }
544
#else
545
        virtual std::size_t get_thread_phase() const noexcept = 0;
546
#endif
547
        virtual std::size_t get_thread_data() const = 0;
548
        virtual std::size_t set_thread_data(std::size_t data) = 0;
549

550
#if defined(HPX_HAVE_LIBCDS)
551
        virtual std::size_t get_libcds_data() const = 0;
552
        virtual std::size_t set_libcds_data(std::size_t data) = 0;
553
        virtual std::size_t get_libcds_hazard_pointer_data() const = 0;
554
        virtual std::size_t set_libcds_hazard_pointer_data(
555
            std::size_t data) = 0;
556
        virtual std::size_t get_libcds_dynamic_hazard_pointer_data() const = 0;
557
        virtual std::size_t set_libcds_dynamic_hazard_pointer_data(
558
            std::size_t data) = 0;
559
#endif
560

561
        virtual void init() = 0;
562
        virtual void rebind(thread_init_data& init_data) = 0;
563

564
#if defined(HPX_HAVE_APEX)
565
        std::shared_ptr<util::external_timer::task_wrapper> get_timer_data()
566
            const noexcept
567
        {
568
            return timer_data_;
569
        }
570
        void set_timer_data(
571
            std::shared_ptr<util::external_timer::task_wrapper> data) noexcept
572
        {
573
            timer_data_ = data;
574
        }
575
#endif
576

577
        // Construct a new \a thread
578
        thread_data(thread_init_data& init_data, void* queue,
579
            std::ptrdiff_t stacksize, bool is_stackless = false,
580
            thread_id_addref addref = thread_id_addref::yes);
581

582
        virtual ~thread_data() override;
583
        virtual void destroy() noexcept = 0;
584

585
    protected:
586
        void rebind_base(thread_init_data& init_data);
587

588
    private:
589
        mutable std::atomic<thread_state> current_state_;
590

591
        ///////////////////////////////////////////////////////////////////////
592
        // Debugging/logging information
593
#ifdef HPX_HAVE_THREAD_DESCRIPTION
594
        threads::thread_description description_;
595
        threads::thread_description lco_description_;
596
#endif
597

598
#ifdef HPX_HAVE_THREAD_PARENT_REFERENCE
599
        std::uint32_t parent_locality_id_;
600
        thread_id_type parent_thread_id_;
601
        std::size_t parent_thread_phase_;
602
#endif
603

604
#ifdef HPX_HAVE_THREAD_MINIMAL_DEADLOCK_DETECTION
605
        mutable thread_schedule_state marked_state_;
606
#endif
607

608
#ifdef HPX_HAVE_THREAD_BACKTRACE_ON_SUSPENSION
609
#ifdef HPX_HAVE_THREAD_FULLBACKTRACE_ON_SUSPENSION
610
        char const* backtrace_;
611
#else
612
        util::backtrace const* backtrace_;
613
#endif
614
#endif
615
        ///////////////////////////////////////////////////////////////////////
616
        thread_priority priority_;
617

618
        bool requested_interrupt_;
619
        bool enabled_interrupt_;
620
        bool ran_exit_funcs_;
621
        bool const is_stackless_;
622

623
        // Singly linked list (heap-allocated)
624
        std::forward_list<hpx::function<void()>> exit_funcs_;
625

626
        // reference to scheduler which created/manages this thread
627
        policies::scheduler_base* scheduler_base_;
628
        std::size_t last_worker_thread_num_;
629

630
        std::ptrdiff_t stacksize_;
631
        thread_stacksize stacksize_enum_;
632

633
        void* queue_;
634

635
    public:
636
#if defined(HPX_HAVE_APEX)
637
        std::shared_ptr<util::external_timer::task_wrapper> timer_data_;
638
#endif
639
    };
640

641
    HPX_FORCEINLINE thread_data* get_thread_id_data(
453,815,089✔
642
        thread_id_ref_type const& tid) noexcept
643
    {
644
        return static_cast<thread_data*>(tid.get().get());
453,827,065✔
645
    }
646

647
    HPX_FORCEINLINE thread_data* get_thread_id_data(
27,869,825✔
648
        thread_id_type const& tid) noexcept
649
    {
650
        return static_cast<thread_data*>(tid.get());
27,869,969✔
651
    }
652

653
    namespace detail {
654

655
        HPX_CORE_EXPORT void set_self_ptr(thread_self*) noexcept;
656
    }
657

658
    ///////////////////////////////////////////////////////////////////////
659
    /// The function \a get_self returns a reference to the (OS thread
660
    /// specific) self reference to the current HPX thread.
661
    HPX_CORE_EXPORT thread_self& get_self();
662

663
    /// The function \a get_self_ptr returns a pointer to the (OS thread
664
    /// specific) self reference to the current HPX thread.
665
    HPX_CORE_EXPORT thread_self* get_self_ptr() noexcept;
666

667
    /// The function \a get_ctx_ptr returns a pointer to the internal data
668
    /// associated with each coroutine.
669
    HPX_CORE_EXPORT thread_self_impl_type* get_ctx_ptr();
670

671
    /// The function \a get_self_ptr_checked returns a pointer to the (OS
672
    /// thread specific) self reference to the current HPX thread.
673
    HPX_CORE_EXPORT thread_self* get_self_ptr_checked(error_code& ec = throws);
674

675
    /// The function \a get_self_id returns the HPX thread id of the current
676
    /// thread (or zero if the current thread is not a HPX thread).
677
    HPX_CORE_EXPORT thread_id_type get_self_id() noexcept;
678

679
    /// The function \a get_parent_id returns the HPX thread id of the
680
    /// current thread's parent (or zero if the current thread is not a
681
    /// HPX thread).
682
    ///
683
    /// \note This function will return a meaningful value only if the
684
    ///       code was compiled with HPX_HAVE_THREAD_PARENT_REFERENCE
685
    ///       being defined.
686
    HPX_CORE_EXPORT thread_id_type get_parent_id() noexcept;
687

688
    /// The function \a get_parent_phase returns the HPX phase of the
689
    /// current thread's parent (or zero if the current thread is not a
690
    /// HPX thread).
691
    ///
692
    /// \note This function will return a meaningful value only if the
693
    ///       code was compiled with HPX_HAVE_THREAD_PARENT_REFERENCE
694
    ///       being defined.
695
    HPX_CORE_EXPORT std::size_t get_parent_phase() noexcept;
696

697
    /// The function \a get_self_stacksize returns the stack size of the
698
    /// current thread (or zero if the current thread is not a HPX thread).
699
    HPX_CORE_EXPORT std::ptrdiff_t get_self_stacksize() noexcept;
700

701
    /// The function \a get_self_stacksize_enum returns the stack size of the /
702
    //current thread (or thread_stacksize::default if the current thread is not
703
    //a HPX thread).
704
    HPX_CORE_EXPORT thread_stacksize get_self_stacksize_enum() noexcept;
705

706
    /// The function \a get_parent_locality_id returns the id of the locality of
707
    /// the current thread's parent (or zero if the current thread is not a
708
    /// HPX thread).
709
    ///
710
    /// \note This function will return a meaningful value only if the
711
    ///       code was compiled with HPX_HAVE_THREAD_PARENT_REFERENCE
712
    ///       being defined.
713
    HPX_CORE_EXPORT std::uint32_t get_parent_locality_id() noexcept;
714

715
    /// The function \a get_self_component_id returns the lva of the component
716
    /// the current thread is acting on
717
    ///
718
    /// \note This function will return a meaningful value only if the code was
719
    ///       compiled with HPX_HAVE_THREAD_TARGET_ADDRESS being defined.
720
    HPX_CORE_EXPORT std::uint64_t get_self_component_id() noexcept;
721
}}    // namespace hpx::threads
722

723
#include <hpx/config/warnings_suffix.hpp>
724

725
#include <hpx/threading_base/thread_data_stackful.hpp>
726
#include <hpx/threading_base/thread_data_stackless.hpp>
727

728
namespace hpx { namespace threads {
729

730
    HPX_FORCEINLINE coroutine_type::result_type thread_data::operator()(
83,596,875✔
731
        hpx::execution_base::this_thread::detail::agent_storage* agent_storage)
732
    {
733
        if (is_stackless())
83,371,827✔
734
        {
735
            return static_cast<thread_data_stackless*>(this)->call();
1✔
736
        }
737
        return static_cast<thread_data_stackful*>(this)->call(agent_storage);
83,446,426✔
738
    }
83,453,998✔
739
}}    // namespace hpx::threads
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc