• 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

82.64
/libs/core/threading_base/src/thread_data.cpp
1
//  Copyright (c) 2007-2021 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/coroutines/detail/coroutine_accessor.hpp>
11
#include <hpx/functional/function.hpp>
12
#include <hpx/lock_registration/detail/register_locks.hpp>
13
#include <hpx/modules/errors.hpp>
14
#include <hpx/modules/logging.hpp>
15
#include <hpx/thread_support/unlock_guard.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 <memory>
25

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

29
    namespace detail {
30

31
        static get_locality_id_type* get_locality_id_f;
32

33
        void set_get_locality_id(get_locality_id_type* f)
1,221✔
34
        {
35
            get_locality_id_f = HPX_MOVE(f);
1,221✔
36
        }
1,221✔
37

38
        std::uint32_t get_locality_id(hpx::error_code& ec)
×
39
        {
40
            if (get_locality_id_f)
×
41
            {
42
                return get_locality_id_f(ec);
×
43
            }
44

45
            // same as naming::invalid_locality_id
46
            return ~static_cast<std::uint32_t>(0);
×
47
        }
×
48
    }    // namespace detail
49

50
    thread_data::thread_data(thread_init_data& init_data, void* queue,
341,290✔
51
        std::ptrdiff_t stacksize, bool is_stackless, thread_id_addref addref)
52
      : detail::thread_data_reference_counting(addref)
341,118✔
53
      , current_state_(thread_state(
682,580✔
54
            init_data.initial_state, thread_restart_state::signaled))
341,118✔
55
#ifdef HPX_HAVE_THREAD_DESCRIPTION
56
      , description_(init_data.description)
57
      , lco_description_()
58
#endif
59
#ifdef HPX_HAVE_THREAD_PARENT_REFERENCE
60
      , parent_locality_id_(init_data.parent_locality_id)
61
      , parent_thread_id_(init_data.parent_id)
62
      , parent_thread_phase_(init_data.parent_phase)
63
#endif
64
#ifdef HPX_HAVE_THREAD_MINIMAL_DEADLOCK_DETECTION
65
      , marked_state_(thread_schedule_state::unknown)
66
#endif
67
#ifdef HPX_HAVE_THREAD_BACKTRACE_ON_SUSPENSION
68
      , backtrace_(nullptr)
69
#endif
70
      , priority_(init_data.priority)
341,118✔
71
      , requested_interrupt_(false)
341,118✔
72
      , enabled_interrupt_(true)
341,118✔
73
      , ran_exit_funcs_(false)
341,118✔
74
      , is_stackless_(is_stackless)
341,118✔
75
      , scheduler_base_(init_data.scheduler_base)
341,118✔
76
      , last_worker_thread_num_(std::size_t(-1))
341,118✔
77
      , stacksize_(stacksize)
341,118✔
78
      , stacksize_enum_(init_data.stacksize)
341,118✔
79
      , queue_(queue)
341,118✔
80
    {
682,580✔
81
        LTM_(debug).format(
661,097✔
82
            "thread::thread({}), description({})", this, get_description());
319,807✔
83

84
        HPX_ASSERT(stacksize_enum_ != threads::thread_stacksize::current);
341,214✔
85

86
#ifdef HPX_HAVE_THREAD_PARENT_REFERENCE
87
        // store the thread id of the parent thread, mainly for debugging
88
        // purposes
89
        if (parent_thread_id_ == nullptr)
90
        {
91
            thread_self* self = get_self_ptr();
92
            if (self)
93
            {
94
                parent_thread_id_ = threads::get_self_id();
95
                parent_thread_phase_ = self->get_thread_phase();
96
            }
97
        }
98
        if (0 == parent_locality_id_)
99
            parent_locality_id_ = detail::get_locality_id(hpx::throws);
100
#endif
101
#if defined(HPX_HAVE_APEX)
102
        set_timer_data(init_data.timer_data);
103
#endif
104
    }
341,189✔
105

106
    thread_data::~thread_data()
341,298✔
107
    {
341,298✔
108
        LTM_(debug).format("thread_data::~thread_data({})", this);
341,298✔
109
        free_thread_exit_callbacks();
341,298✔
110
    }
341,298✔
111

112
    void thread_data::destroy_thread()
5,757,407✔
113
    {
114
        LTM_(debug).format(
11,505,505✔
115
            "thread_data::destroy_thread({}), description({}), phase({})", this,
5,748,098✔
116
            this->get_description(), this->get_thread_phase());
5,748,108✔
117

118
        get_scheduler_base()->destroy_thread(this);
5,757,394✔
119
    }
5,757,405✔
120

121
    void thread_data::run_thread_exit_callbacks()
4,843,231✔
122
    {
123
        std::unique_lock<hpx::util::detail::spinlock> l(
4,843,319✔
124
            spinlock_pool::spinlock_for(this));
4,843,319✔
125

126
        while (!exit_funcs_.empty())
4,843,617✔
127
        {
128
            {
129
                hpx::unlock_guard<std::unique_lock<hpx::util::detail::spinlock>>
130
                    ul(l);
386✔
131
                if (!exit_funcs_.front().empty())
386✔
132
                    exit_funcs_.front()();
386✔
133
            }
386✔
134
            exit_funcs_.pop_front();
386✔
135
        }
136
        ran_exit_funcs_ = true;
4,843,255✔
137
    }
4,843,281✔
138

139
    bool thread_data::add_thread_exit_callback(hpx::function<void()> const& f)
1,135✔
140
    {
141
        std::lock_guard<hpx::util::detail::spinlock> l(
1,135✔
142
            spinlock_pool::spinlock_for(this));
1,135✔
143

144
        if (ran_exit_funcs_ ||
1,135✔
145
            get_state().state() == thread_schedule_state::terminated)
386✔
146
        {
147
            return false;
749✔
148
        }
149

150
        exit_funcs_.push_front(f);
386✔
151

152
        return true;
386✔
153
    }
1,135✔
154

155
    void thread_data::free_thread_exit_callbacks()
10,737,050✔
156
    {
157
        std::lock_guard<hpx::util::detail::spinlock> l(
10,737,496✔
158
            spinlock_pool::spinlock_for(this));
10,737,496✔
159

160
        // Exit functions should have been executed.
161
        HPX_ASSERT(exit_funcs_.empty() || ran_exit_funcs_);
10,737,050✔
162

163
        exit_funcs_.clear();
10,737,247✔
164
    }
10,737,247✔
165

166
    bool thread_data::interruption_point(bool throw_on_interrupt)
154,667,494✔
167
    {
168
        // We do not protect enabled_interrupt_ and requested_interrupt_ from
169
        // concurrent access here (which creates a benign data race) in order to
170
        // avoid infinite recursion. This function is called by
171
        // this_thread::suspend which causes problems if the lock would call
172
        // suspend itself.
173
        if (enabled_interrupt_ && requested_interrupt_)
154,667,494✔
174
        {
175
            // Verify that there are no more registered locks for this
176
            // OS-thread. This will throw if there are still any locks held.
177
            util::force_error_on_lock();
5✔
178

179
            // now interrupt this thread
180
            if (throw_on_interrupt)
5✔
181
            {
182
                requested_interrupt_ = false;    // avoid recursive exceptions
×
183
                throw hpx::thread_interrupted();
×
184
            }
185

186
            return true;
×
187
        }
188
        return false;
155,058,961✔
189
    }
155,063,607✔
190

191
    void thread_data::rebind_base(thread_init_data& init_data)
5,553,623✔
192
    {
193
        LTM_(debug).format(
11,101,524✔
194
            "thread_data::rebind_base({}), description({}), phase({}), rebind",
5,547,901✔
195
            this, get_description(), get_thread_phase());
5,547,970✔
196

197
        free_thread_exit_callbacks();
5,553,969✔
198

199
        current_state_.store(thread_state(
11,107,898✔
200
            init_data.initial_state, thread_restart_state::signaled));
5,553,969✔
201

202
#ifdef HPX_HAVE_THREAD_DESCRIPTION
203
        description_ = init_data.description;
204
        lco_description_ = threads::thread_description();
205
#endif
206
#ifdef HPX_HAVE_THREAD_PARENT_REFERENCE
207
        parent_locality_id_ = init_data.parent_locality_id;
208
        parent_thread_id_ = init_data.parent_id;
209
        parent_thread_phase_ = init_data.parent_phase;
210
#endif
211
#ifdef HPX_HAVE_THREAD_MINIMAL_DEADLOCK_DETECTION
212
        set_marked_state(thread_schedule_state::unknown);
213
#endif
214
#ifdef HPX_HAVE_THREAD_BACKTRACE_ON_SUSPENSION
215
        backtrace_ = nullptr;
216
#endif
217
        priority_ = init_data.priority;
5,553,969✔
218
        requested_interrupt_ = false;
5,553,969✔
219
        enabled_interrupt_ = true;
5,553,969✔
220
        ran_exit_funcs_ = false;
5,553,969✔
221
        exit_funcs_.clear();
5,553,969✔
222
        scheduler_base_ = init_data.scheduler_base;
5,553,969✔
223
        last_worker_thread_num_ = std::size_t(-1);
5,553,969✔
224

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;
5,553,969✔
229
        HPX_ASSERT(stacksize_ == get_stack_size());
5,553,949✔
230
        HPX_ASSERT(stacksize_ != 0);
5,553,970✔
231

232
        LTM_(debug).format("thread::thread({}), description({}), rebind", this,
5,553,970✔
233
            get_description());
5,548,388✔
234

235
#ifdef HPX_HAVE_THREAD_PARENT_REFERENCE
236
        // store the thread id of the parent thread, mainly for debugging
237
        // purposes
238
        if (parent_thread_id_ == nullptr)
239
        {
240
            thread_self* self = get_self_ptr();
241
            if (self)
242
            {
243
                parent_thread_id_ = threads::get_self_id();
244
                parent_thread_phase_ = self->get_thread_phase();
245
            }
246
        }
247
        if (0 == parent_locality_id_)
248
        {
249
            parent_locality_id_ = detail::get_locality_id(hpx::throws);
250
        }
251
#endif
252
#if defined(HPX_HAVE_APEX)
253
        set_timer_data(init_data.timer_data);
254
#endif
255
    }
5,553,963✔
256

257
    ///////////////////////////////////////////////////////////////////////////
258
    thread_self& get_self()
2,119,723✔
259
    {
260
        thread_self* p = get_self_ptr();
2,119,723✔
261
        if (HPX_UNLIKELY(p == nullptr))
2,119,687✔
262
        {
263
            HPX_THROW_EXCEPTION(hpx::error::null_thread_id, "threads::get_self",
×
264
                "null thread id encountered (is this executed on a "
265
                "HPX-thread?)");
266
        }
267
        return *p;
2,119,706✔
268
    }
×
269

270
    thread_self* get_self_ptr() noexcept
629,170,693✔
271
    {
272
        return thread_self::get_self();
629,170,693✔
273
    }
274

275
    namespace detail {
276

277
        void set_self_ptr(thread_self* self) noexcept
×
278
        {
279
            thread_self::set_self(self);
×
280
        }
×
281
    }    // namespace detail
282

283
    thread_self::impl_type* get_ctx_ptr()
8✔
284
    {
285
        using hpx::threads::coroutines::detail::coroutine_accessor;
286
        return coroutine_accessor::get_impl(get_self());
8✔
287
    }
288

289
    thread_self* get_self_ptr_checked(error_code& ec)
×
290
    {
291
        thread_self* p = thread_self::get_self();
×
292

293
        if (HPX_UNLIKELY(p == nullptr))
×
294
        {
295
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
×
296
                "threads::get_self_ptr_checked",
297
                "null thread id encountered (is this executed on a "
298
                "HPX-thread?)");
299
            return nullptr;
×
300
        }
301

302
        if (&ec != &throws)
×
303
            ec = make_success_code();
×
304

305
        return p;
×
306
    }
×
307

308
    thread_id_type get_self_id() noexcept
18,882,170✔
309
    {
310
        thread_self* self = get_self_ptr();
18,879,754✔
311
        if (HPX_LIKELY(nullptr != self))
18,879,754✔
312
            return self->get_thread_id();
18,877,772✔
313

314
        return threads::invalid_thread_id;
1,516✔
315
    }
18,879,308✔
316

317
    thread_data* get_self_id_data() noexcept
9,766,305✔
318
    {
319
        thread_self* self = get_self_ptr();
9,766,305✔
320
        if (HPX_LIKELY(nullptr != self))
9,766,258✔
321
            return get_thread_id_data(self->get_thread_id());
8,522,583✔
322

323
        return nullptr;
1,243,597✔
324
    }
9,766,009✔
325

326
    std::ptrdiff_t get_self_stacksize() noexcept
×
327
    {
328
        thread_data* thrd_data = get_self_id_data();
×
329
        return thrd_data ? thrd_data->get_stack_size() : 0;
×
330
    }
331

332
    thread_stacksize get_self_stacksize_enum() noexcept
745✔
333
    {
334
        thread_data* thrd_data = get_self_id_data();
745✔
335
        thread_stacksize stacksize = thrd_data ?
745✔
336
            thrd_data->get_stack_size_enum() :
502✔
337
            thread_stacksize::default_;
338
        HPX_ASSERT(stacksize != thread_stacksize::current);
745✔
339
        return stacksize;
745✔
340
    }
341

342
#ifndef HPX_HAVE_THREAD_PARENT_REFERENCE
343
    thread_id_type get_parent_id() noexcept
57,520,073✔
344
    {
345
        return threads::invalid_thread_id;
57,520,004✔
346
    }
347

348
    std::size_t get_parent_phase() noexcept
57,531,747✔
349
    {
350
        return 0;
57,531,747✔
351
    }
352

353
    std::uint32_t get_parent_locality_id() noexcept
57,507,424✔
354
    {
355
        // same as naming::invalid_locality_id
356
        return ~static_cast<std::uint32_t>(0);
57,507,424✔
357
    }
358
#else
359
    thread_id_type get_parent_id() noexcept
360
    {
361
        thread_data* thrd_data = get_self_id_data();
362
        if (HPX_LIKELY(nullptr != thrd_data))
363
        {
364
            return thrd_data->get_parent_thread_id();
365
        }
366
        return threads::invalid_thread_id;
367
    }
368

369
    std::size_t get_parent_phase() noexcept
370
    {
371
        thread_data* thrd_data = get_self_id_data();
372
        if (HPX_LIKELY(nullptr != thrd_data))
373
        {
374
            return thrd_data->get_parent_thread_phase();
375
        }
376
        return 0;
377
    }
378

379
    std::uint32_t get_parent_locality_id() noexcept
380
    {
381
        thread_data* thrd_data = get_self_id_data();
382
        if (HPX_LIKELY(nullptr != thrd_data))
383
        {
384
            return thrd_data->get_parent_locality_id();
385
        }
386

387
        // same as naming::invalid_locality_id
388
        return ~static_cast<std::uint32_t>(0);
389
    }
390
#endif
391

392
    std::uint64_t get_self_component_id() noexcept
31,665,525✔
393
    {
394
#ifndef HPX_HAVE_THREAD_TARGET_ADDRESS
395
        return 0;
31,665,525✔
396
#else
397
        thread_data* thrd_data = get_self_id_data();
398
        if (HPX_LIKELY(nullptr != thrd_data))
399
        {
400
            return thrd_data->get_component_id();
401
        }
402
        return 0;
403
#endif
404
    }
405

406
#if defined(HPX_HAVE_APEX)
407
    std::shared_ptr<hpx::util::external_timer::task_wrapper>
408
    get_self_timer_data()
409
    {
410
        thread_data* thrd_data = get_self_id_data();
411
        if (HPX_LIKELY(nullptr != thrd_data))
412
        {
413
            return thrd_data->get_timer_data();
414
        }
415
        return nullptr;
416
    }
417

418
    void set_self_timer_data(
419
        std::shared_ptr<hpx::util::external_timer::task_wrapper> data)
420
    {
421
        thread_data* thrd_data = get_self_id_data();
422
        if (HPX_LIKELY(nullptr != thrd_data))
423
        {
424
            thrd_data->set_timer_data(data);
425
        }
426
        return;
427
    }
428
#endif
429
}    // 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