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

STEllAR-GROUP / hpx / #882

31 Aug 2023 07:44PM UTC coverage: 41.798% (-44.7%) from 86.546%
#882

push

19442 of 46514 relevant lines covered (41.8%)

126375.38 hits per line

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

69.3
/libs/core/threading_base/src/thread_data.cpp
1
//  Copyright (c) 2007-2025 Hartmut Kaiser
2
//  Copyright (c) 2008-2009 Chirag Dekate, Anshul Tandon
3
//  Copyright (c) 2011      Bryce Lelbach
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
#include <hpx/assert.hpp>
10
#include <hpx/modules/coroutines.hpp>
11
#include <hpx/modules/errors.hpp>
12
#include <hpx/modules/functional.hpp>
13
#include <hpx/modules/lock_registration.hpp>
14
#include <hpx/modules/logging.hpp>
15
#include <hpx/modules/thread_support.hpp>
16
#include <hpx/threading_base/scheduler_base.hpp>
17
#include <hpx/threading_base/thread_data.hpp>
18
#if defined(HPX_HAVE_APEX)
19
#include <hpx/threading_base/external_timer.hpp>
20
#endif
21

22
#include <cstddef>
23
#include <cstdint>
24
#include <limits>
25
#include <memory>
26

27
////////////////////////////////////////////////////////////////////////////////
28
namespace hpx::threads {
29

30
    namespace detail {
31

32
        namespace {
33

64✔
34
            get_locality_id_type* get_locality_id_f = nullptr;
35
        }
64✔
36

64✔
37
        void set_get_locality_id(get_locality_id_type* f)
38
        {
×
39
            get_locality_id_f = HPX_MOVE(f);
40
        }
×
41

42
        std::uint32_t get_locality_id(hpx::error_code& ec)
×
43
        {
44
            if (get_locality_id_f)
45
            {
46
                return get_locality_id_f(ec);
47
            }
48

49
            // same as naming::invalid_locality_id
50
            return ~static_cast<std::uint32_t>(0);
8,397✔
51
        }
8,397✔
52
    }    // namespace detail
53

8,397✔
54
    thread_data::thread_data(thread_init_data& init_data, void* queue,
55
        std::ptrdiff_t stacksize, bool is_stackless, thread_id_addref addref)
56
      : detail::thread_data_reference_counting(addref)
57
      , priority_(init_data.priority)
58
      , requested_interrupt_(false)
59
      , enabled_interrupt_(true)
60
      , ran_exit_funcs_(false)
61
      , is_stackless_(is_stackless)
62
      , runs_as_child_(init_data.schedulehint.runs_as_child_mode() ==
63
            hpx::threads::thread_execution_hint::run_as_child)
64
      , last_worker_thread_num_(
65
            init_data.schedulehint.mode == thread_schedule_hint_mode::thread ?
66
                init_data.schedulehint.hint :
67
                static_cast<std::uint16_t>(-1))
68
      , stacksize_enum_(init_data.stacksize)
69
      , stacksize_(stacksize_enum_ == thread_stacksize::nostack ?
70
                (std::numeric_limits<std::int32_t>::max)() :
8,397✔
71
                static_cast<std::int32_t>(stacksize))
8,397✔
72
      , current_state_(thread_state(
8,397✔
73
            init_data.initial_state, thread_restart_state::signaled))
8,397✔
74
      , scheduler_base_(init_data.scheduler_base)
8,397✔
75
      , queue_(queue)
8,397✔
76
#ifdef HPX_HAVE_THREAD_DESCRIPTION
77
      , description_(init_data.description)
8,397✔
78
#endif
8,397✔
79
#ifdef HPX_HAVE_THREAD_MINIMAL_DEADLOCK_DETECTION
8,397✔
80
      , marked_state_(thread_schedule_state::unknown)
8,397✔
81
#endif
8,397✔
82
#ifdef HPX_HAVE_THREAD_PARENT_REFERENCE
83
      , parent_locality_id_(init_data.parent_locality_id)
8,397✔
84
      , parent_thread_id_(init_data.parent_id)
×
85
      , parent_thread_phase_(init_data.parent_phase)
86
#endif
87
    {
88
        LTM_(debug).format(
89
            "thread::thread({}), description({})", this, get_description());
90

91
        HPX_ASSERT(is_stackless_ ||
92
            stacksize <= (std::numeric_limits<std::int32_t>::max)());
93
        HPX_ASSERT(stacksize_enum_ != threads::thread_stacksize::current);
94

95
#ifdef HPX_HAVE_THREAD_PARENT_REFERENCE
96
        // store the thread id of the parent thread, mainly for debugging
97
        // purposes
98
        if (parent_thread_id_ == nullptr)
99
        {
100
            if (thread_self const* self = get_self_ptr())
101
            {
102
                parent_thread_id_ = threads::get_self_id();
103
                parent_thread_phase_ = self->get_thread_phase();
104
            }
105
        }
8,397✔
106
        if (0 == parent_locality_id_)
107
            parent_locality_id_ = detail::get_locality_id(hpx::throws);
8,397✔
108
#endif
109
#if defined(HPX_HAVE_APEX)
8,397✔
110
        set_timer_data(init_data.timer_data);
8,397✔
111
#endif
8,397✔
112
    }
113

43,912✔
114
    thread_data::~thread_data()
115
    {
43,912✔
116
        LTM_(debug).format("thread_data::~thread_data({})", this);
×
117
        free_thread_exit_callbacks();
×
118
    }
119

43,912✔
120
    void thread_data::destroy_thread()
43,912✔
121
    {
122
        LTM_(debug).format(
2,507✔
123
            "thread_data::destroy_thread({}), description({}), phase({})", this,
124
            this->get_description(), this->get_thread_phase());
125

126
        get_scheduler_base()->destroy_thread(this);
127
    }
2,516✔
128

129
    void thread_data::run_thread_exit_callbacks()
130
    {
131
        std::unique_lock<hpx::util::detail::spinlock> l(
132
            spinlock_pool::spinlock_for(this));
9✔
133

134
        while (!exit_funcs_.empty())
135
        {
136
            {
137
                hpx::unlock_guard<std::unique_lock<hpx::util::detail::spinlock>>
2,507✔
138
                    ul(l);
2,507✔
139
                if (!exit_funcs_.front().empty())
140
                    exit_funcs_.front()();
12✔
141
            }
142
            exit_funcs_.pop_front();
143
        }
12✔
144
        ran_exit_funcs_ = true;
145
    }
9✔
146

21✔
147
    bool thread_data::add_thread_exit_callback(hpx::function<void()> const& f)
148
    {
149
        std::lock_guard<hpx::util::detail::spinlock> l(
3✔
150
            spinlock_pool::spinlock_for(this));
151

152
        if (ran_exit_funcs_ ||
153
            get_state().state() == thread_schedule_state::terminated ||
154
            get_state().state() == thread_schedule_state::deleted)
9✔
155
        {
156
            return false;
157
        }
50,959✔
158

159
        exit_funcs_.push_front(f);
160

50,959✔
161
        return true;
162
    }
163

164
    void thread_data::free_thread_exit_callbacks()
165
    {
166
        std::lock_guard<hpx::util::detail::spinlock> l(
50,959✔
167
            spinlock_pool::spinlock_for(this));
168

3,574,222✔
169
        // Exit functions should have been executed.
170
        HPX_ASSERT(exit_funcs_.empty() || ran_exit_funcs_);
171

172
        exit_funcs_.clear();
173
    }
174

175
    bool thread_data::interruption_point(bool throw_on_interrupt)
3,574,222✔
176
    {
177
        // We do not protect enabled_interrupt_ and requested_interrupt_ from
178
        // concurrent access here (which creates a benign data race) in order to
179
        // avoid infinite recursion. This function is called by
180
        // this_thread::suspend which causes problems if the lock would call
181
        // suspend itself.
182
        if (enabled_interrupt_ && requested_interrupt_)
×
183
        {
184
            // Verify that there are no more registered locks for this
×
185
            // OS-thread. This will throw if there are still any locks held.
×
186
            util::force_error_on_lock();
187

188
            // now interrupt this thread
189
            if (throw_on_interrupt)
190
            {
191
                requested_interrupt_ = false;    // avoid recursive exceptions
192
                throw hpx::thread_interrupted();
193
            }
40,055✔
194

195
            return true;
40,055✔
196
        }
197
        return false;
×
198
    }
199

40,055✔
200
    void thread_data::rebind_base(thread_init_data& init_data)
201
    {
40,055✔
202
        LTM_(debug).format(
203
            "thread_data::rebind_base({}), description({}), phase({}), rebind",
204
            this, get_description(), get_thread_phase());
205

206
        free_thread_exit_callbacks();
207

208
        priority_ = init_data.priority;
209
        requested_interrupt_ = false;
210
        enabled_interrupt_ = true;
211
        ran_exit_funcs_ = false;
212

213
        runs_as_child_.store(init_data.schedulehint.runs_as_child_mode() ==
214
                hpx::threads::thread_execution_hint::run_as_child,
215
            std::memory_order_relaxed);
216

217
        last_worker_thread_num_ =
218
            init_data.schedulehint.mode == thread_schedule_hint_mode::thread ?
219
            init_data.schedulehint.hint :
40,055✔
220
            static_cast<std::uint16_t>(-1);
40,055✔
221

40,055✔
222
        exit_funcs_.clear();
40,055✔
223
        scheduler_base_ = init_data.scheduler_base;
224

40,055✔
225
        // We explicitly set the logical stack size again as it can be different
226
        // from what the previous use required. However, the physical stack size
227
        // must be the same as before.
228
        stacksize_enum_ = init_data.stacksize;
229

40,055✔
230
        HPX_ASSERT(stacksize_enum_ == thread_stacksize::nostack ||
40,055✔
231
            stacksize_ == get_stack_size());
232
        HPX_ASSERT(stacksize_ != 0);
233

234
        current_state_.store(thread_state(
235
            init_data.initial_state, thread_restart_state::signaled));
40,055✔
236

237
#ifdef HPX_HAVE_THREAD_DESCRIPTION
238
        description_ = init_data.description;
239
        lco_description_ = threads::thread_description();
40,055✔
240
#endif
×
241
#ifdef HPX_HAVE_THREAD_PARENT_REFERENCE
242
        parent_locality_id_ = init_data.parent_locality_id;
243
        parent_thread_id_ = init_data.parent_id;
244
        parent_thread_phase_ = init_data.parent_phase;
245
#endif
246
#ifdef HPX_HAVE_THREAD_MINIMAL_DEADLOCK_DETECTION
247
        set_marked_state(thread_schedule_state::unknown);
248
#endif
249
#ifdef HPX_HAVE_THREAD_BACKTRACE_ON_SUSPENSION
250
        backtrace_ = nullptr;
251
#endif
252

253
        LTM_(debug).format("thread::thread({}), description({}), rebind", this,
254
            get_description());
255

256
#ifdef HPX_HAVE_THREAD_PARENT_REFERENCE
257
        // store the thread id of the parent thread, mainly for debugging
258
        // purposes
259
        if (parent_thread_id_ == nullptr)
260
        {
261
            if (thread_self const* self = get_self_ptr())
40,055✔
262
            {
263
                parent_thread_id_ = threads::get_self_id();
264
                parent_thread_phase_ = self->get_thread_phase();
1,073,016✔
265
            }
266
        }
1,073,016✔
267
        if (0 == parent_locality_id_)
1,073,016✔
268
        {
269
            parent_locality_id_ = detail::get_locality_id(hpx::throws);
×
270
        }
271
#endif
272
#if defined(HPX_HAVE_APEX)
273
        set_timer_data(init_data.timer_data);
1,073,016✔
274
#endif
275
    }
276

1,603,585✔
277
    ///////////////////////////////////////////////////////////////////////////
278
    thread_self& get_self()
1,603,585✔
279
    {
280
        thread_self* p = get_self_ptr();
281
        if (HPX_UNLIKELY(p == nullptr))
282
        {
283
            HPX_THROW_EXCEPTION(hpx::error::null_thread_id, "threads::get_self",
×
284
                "null thread id encountered (is this executed on a "
285
                "HPX-thread?)");
286
        }
×
287
        return *p;
288
    }
289

×
290
    thread_self* get_self_ptr() noexcept
291
    {
292
        return thread_self::get_self();
×
293
    }
294

295
    namespace detail {
×
296

297
        void set_self_ptr(thread_self* self) noexcept
298
        {
299
            thread_self::set_self(self);
×
300
        }
301
    }    // namespace detail
×
302

303
    thread_self::impl_type* get_ctx_ptr()
304
    {
305
        using hpx::threads::coroutines::detail::coroutine_accessor;
×
306
        return coroutine_accessor::get_impl(get_self());
307
    }
308

×
309
    thread_self* get_self_ptr_checked(error_code& ec)
×
310
    {
311
        thread_self* p = thread_self::get_self();
312

313
        if (HPX_UNLIKELY(p == nullptr))
314
        {
143,033✔
315
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
316
                "threads::get_self_ptr_checked",
143,033✔
317
                "null thread id encountered (is this executed on a "
143,033✔
318
                "HPX-thread?)");
319
            return nullptr;
143,033✔
320
        }
321

×
322
        if (&ec != &throws)
323
            ec = make_success_code();
324

186✔
325
        return p;
326
    }
186✔
327

186✔
328
    thread_id_type get_self_id() noexcept
329
    {
186✔
330
        if (thread_self const* self = get_self_ptr();
331
            HPX_LIKELY(nullptr != self))
×
332
        {
333
            return self->get_thread_id();
334
        }
46,100✔
335
        return threads::invalid_thread_id;
336
    }
46,100✔
337

46,100✔
338
    thread_id_type get_outer_self_id() noexcept
339
    {
45,728✔
340
        if (thread_self const* self = get_self_ptr();
341
            HPX_LIKELY(nullptr != self))
342
        {
343
            return self->get_outer_thread_id();
344
        }
×
345
        return threads::invalid_thread_id;
346
    }
×
347

×
348
    thread_data* get_self_id_data() noexcept
349
    {
350
        if (thread_self const* self = get_self_ptr();
2✔
351
            HPX_LIKELY(nullptr != self))
352
        {
2✔
353
            return get_thread_id_data(self->get_thread_id());
2✔
354
        }
355
        return nullptr;
356
    }
357

2✔
358
    std::ptrdiff_t get_self_stacksize() noexcept
359
    {
360
        thread_data const* thrd_data = get_self_id_data();
361
        return thrd_data ? thrd_data->get_stack_size() : 0;
×
362
    }
363

×
364
    thread_stacksize get_self_stacksize_enum() noexcept
365
    {
366
        thread_data const* thrd_data = get_self_id_data();
×
367
        thread_stacksize const stacksize = thrd_data ?
368
            thrd_data->get_stack_size_enum() :
×
369
            thread_stacksize::default_;
370
        HPX_ASSERT(stacksize != thread_stacksize::current);
371
        return stacksize;
×
372
    }
373

374
#ifndef HPX_HAVE_THREAD_PARENT_REFERENCE
×
375
    thread_id_type get_parent_id() noexcept
376
    {
377
        return threads::invalid_thread_id;
378
    }
379

380
    std::size_t get_parent_phase() noexcept
381
    {
382
        return 0;
383
    }
384

385
    std::uint32_t get_parent_locality_id() noexcept
386
    {
387
        // same as naming::invalid_locality_id
388
        return ~static_cast<std::uint32_t>(0);
389
    }
390
#else
391
    thread_id_type get_parent_id() noexcept
392
    {
393
        if (thread_data const* thrd_data = get_self_id_data();
394
            HPX_LIKELY(nullptr != thrd_data))
395
        {
396
            return thrd_data->get_parent_thread_id();
397
        }
398
        return threads::invalid_thread_id;
399
    }
400

401
    std::size_t get_parent_phase() noexcept
402
    {
403
        if (thread_data const* thrd_data = get_self_id_data();
404
            HPX_LIKELY(nullptr != thrd_data))
405
        {
406
            return thrd_data->get_parent_thread_phase();
407
        }
408
        return 0;
409
    }
410

×
411
    std::uint32_t get_parent_locality_id() noexcept
412
    {
413
        if (thread_data const* thrd_data = get_self_id_data();
×
414
            HPX_LIKELY(nullptr != thrd_data))
415
        {
416
            return thrd_data->get_parent_locality_id();
417
        }
418

419
        // same as naming::invalid_locality_id
420
        return ~static_cast<std::uint32_t>(0);
421
    }
422
#endif
423

424
    std::uint64_t get_self_component_id() noexcept
425
    {
426
#ifndef HPX_HAVE_THREAD_TARGET_ADDRESS
427
        return 0;
428
#else
429
        if (thread_data const* thrd_data = get_self_id_data();
430
            HPX_LIKELY(nullptr != thrd_data))
431
        {
432
            return thrd_data->get_component_id();
433
        }
434
        return 0;
435
#endif
436
    }
437

438
#if defined(HPX_HAVE_APEX)
439
    std::shared_ptr<hpx::util::external_timer::task_wrapper>
440
    get_self_timer_data()
441
    {
442
        if (thread_data* thrd_data = get_self_id_data();
443
            HPX_LIKELY(nullptr != thrd_data))
444
        {
445
            return thrd_data->get_timer_data();
446
        }
447
        return nullptr;
448
    }
449

450
    void set_self_timer_data(
451
        std::shared_ptr<hpx::util::external_timer::task_wrapper> data)
452
    {
453
        if (thread_data* thrd_data = get_self_id_data();
454
            HPX_LIKELY(nullptr != thrd_data))
455
        {
456
            thrd_data->set_timer_data(data);
457
        }
458
    }
459
#endif
460
}    // 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

© 2025 Coveralls, Inc