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

STEllAR-GROUP / hpx / #853

19 Dec 2022 01:01AM UTC coverage: 86.287% (+0.4%) from 85.912%
#853

push

StellarBot
Merge #6109

6109: Modernize serialization module r=hkaiser a=hkaiser

- flyby separate serialization of Boost types

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

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

53 of 53 new or added lines in 6 files covered. (100.0%)

173939 of 201582 relevant lines covered (86.29%)

1931657.12 hits per line

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

58.02
/libs/core/threading/src/thread.cpp
1
//  Copyright (c) 2007-2021 Hartmut Kaiser
2
//
3
//  SPDX-License-Identifier: BSL-1.0
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/assert.hpp>
8
#include <hpx/functional/bind.hpp>
9
#include <hpx/functional/bind_front.hpp>
10
#include <hpx/functional/move_only_function.hpp>
11
#include <hpx/futures/detail/future_data.hpp>
12
#include <hpx/futures/future.hpp>
13
#include <hpx/lock_registration/detail/register_locks.hpp>
14
#include <hpx/modules/errors.hpp>
15
#include <hpx/modules/memory.hpp>
16
#include <hpx/modules/threading.hpp>
17
#include <hpx/thread_support/unlock_guard.hpp>
18
#include <hpx/threading_base/thread_helpers.hpp>
19
#include <hpx/threading_base/thread_init_data.hpp>
20
#include <hpx/threading_base/thread_pool_base.hpp>
21
#include <hpx/timing/steady_clock.hpp>
22

23
#include <cstddef>
24
#include <exception>
25
#include <functional>
26
#include <mutex>
27
#include <utility>
28

29
#if defined(__ANDROID__) || defined(ANDROID)
30
#include <cpu-features.h>
31
#endif
32

33
namespace hpx {
34
    namespace detail {
35
        static thread_termination_handler_type thread_termination_handler;
1,249✔
36
    }
37

38
    void set_thread_termination_handler(thread_termination_handler_type f)
1,219✔
39
    {
40
        detail::thread_termination_handler = f;
1,219✔
41
    }
1,219✔
42

43
    thread::thread() noexcept
5✔
44
      : id_(hpx::threads::invalid_thread_id)
5✔
45
    {
46
    }
5✔
47

48
    thread::thread(thread&& rhs) noexcept
203✔
49
    {
50
        std::lock_guard l(rhs.mtx_);
203✔
51
        id_ = rhs.id_;
203✔
52
        rhs.id_ = threads::invalid_thread_id;
203✔
53
    }
203✔
54

55
    thread& thread::operator=(thread&& rhs) noexcept
5✔
56
    {
57
        std::unique_lock l(mtx_);
5✔
58
        std::unique_lock l2(rhs.mtx_);
5✔
59
        if (joinable_locked())
5✔
60
        {
61
            l2.unlock();
×
62
            l.unlock();
×
63
            HPX_THROW_EXCEPTION(hpx::error::invalid_status,
×
64
                "thread::operator=", "destroying running thread");
65
        }
66
        id_ = rhs.id_;
5✔
67
        rhs.id_ = threads::invalid_thread_id;
5✔
68
        return *this;
69
    }
5✔
70

71
    thread::~thread()
1,343✔
72
    {
73
        if (joinable())
1,343✔
74
        {
75
            if (detail::thread_termination_handler)
×
76
            {
77
                try
78
                {
79
                    HPX_THROW_EXCEPTION(hpx::error::invalid_status,
×
80
                        "thread::~thread", "destroying running thread");
81
                }
×
82
                catch (...)
83
                {
84
                    detail::thread_termination_handler(
×
85
                        std::current_exception());
×
86
                }
×
87
            }
×
88
            else
89
            {
90
                std::terminate();
×
91
            }
92
        }
×
93

94
        HPX_ASSERT(id_ == threads::invalid_thread_id);
1,343✔
95
    }
1,343✔
96

97
    void thread::swap(thread& rhs) noexcept
2✔
98
    {
99
        std::lock_guard l(mtx_);
2✔
100
        std::lock_guard l2(rhs.mtx_);
2✔
101
        std::swap(id_, rhs.id_);
2✔
102
    }
2✔
103

104
    static void run_thread_exit_callbacks()
1,135✔
105
    {
106
        threads::thread_id_type id = threads::get_self_id();
1,135✔
107
        if (id == threads::invalid_thread_id)
1,135✔
108
        {
109
            HPX_THROW_EXCEPTION(hpx::error::null_thread_id,
×
110
                "run_thread_exit_callbacks", "null thread id encountered");
111
        }
112
        threads::run_thread_exit_callbacks(id);
1,135✔
113
        threads::free_thread_exit_callbacks(id);
1,135✔
114
    }
1,135✔
115

116
    threads::thread_result_type thread::thread_function_nullary(
1,135✔
117
        hpx::move_only_function<void()> const& func)
118
    {
119
        try
120
        {
121
            // Now notify our calling thread that we started execution.
122
            func();
1,135✔
123
        }
1,135✔
124
        catch (hpx::thread_interrupted const&)
125
        {    //-V565
126
            /* swallow this exception */
127
        }
1✔
128
        catch (hpx::exception const&)
129
        {
130
            // Verify that there are no more registered locks for this
131
            // OS-thread. This will throw if there are still any locks
132
            // held.
133
            util::force_error_on_lock();
×
134

135
            // run all callbacks attached to the exit event for this thread
136
            run_thread_exit_callbacks();
×
137

138
            throw;    // rethrow any exception except 'thread_interrupted'
×
139
        }
1✔
140

141
        // Verify that there are no more registered locks for this
142
        // OS-thread. This will throw if there are still any locks
143
        // held.
144
        util::force_error_on_lock();
1,135✔
145

146
        // run all callbacks attached to the exit event for this thread
147
        run_thread_exit_callbacks();
1,135✔
148

149
        return threads::thread_result_type(
1,135✔
150
            threads::thread_schedule_state::terminated,
1,135✔
151
            threads::invalid_thread_id);
152
    }
1✔
153

154
    thread::id thread::get_id() const noexcept
86✔
155
    {
156
        return id(native_handle());
86✔
157
    }
158

159
    unsigned int thread::hardware_concurrency() noexcept
2✔
160
    {
161
        return hpx::threads::hardware_concurrency();
2✔
162
    }
163

164
    void thread::start_thread(
1,135✔
165
        threads::thread_pool_base* pool, hpx::move_only_function<void()>&& func)
166
    {
167
        HPX_ASSERT(pool);
1,135✔
168

169
        threads::thread_init_data data(
1,135✔
170
            util::one_shot(
1,135✔
171
                hpx::bind(&thread::thread_function_nullary, HPX_MOVE(func))),
1,135✔
172
            "thread::thread_function_nullary",
1,135✔
173
            threads::thread_priority::default_, threads::thread_schedule_hint(),
1,135✔
174
            threads::thread_stacksize::default_,
175
            threads::thread_schedule_state::pending, true);
176

177
        // create the new thread, note that id_ is guaranteed to be valid
178
        // before the thread function is executed
179
        error_code ec(throwmode::lightweight);
1,135✔
180
        pool->create_thread(data, id_, ec);
1,135✔
181
        if (ec)
1,135✔
182
        {
183
            HPX_THROW_EXCEPTION(hpx::error::thread_resource_error,
×
184
                "thread::start_thread", "Could not create thread");
185
            return;
186
        }
187
    }
1,135✔
188

189
    static void resume_thread(threads::thread_id_ref_type const& id)
381✔
190
    {
191
        threads::set_thread_state(
381✔
192
            id.noref(), threads::thread_schedule_state::pending);
381✔
193
    }
381✔
194

195
    void thread::join()
1,135✔
196
    {
197
        std::unique_lock l(mtx_);
1,135✔
198

199
        if (!joinable_locked())
1,135✔
200
        {
201
            l.unlock();
1✔
202
            HPX_THROW_EXCEPTION(hpx::error::invalid_status, "thread::join",
1✔
203
                "trying to join a non joinable thread");
204
        }
205

206
        // keep ourselves alive while being suspended
207
        threads::thread_id_ref_type this_id = threads::get_self_id();
1,134✔
208
        if (this_id == id_)
1,134✔
209
        {
210
            l.unlock();
×
211
            HPX_THROW_EXCEPTION(hpx::error::thread_resource_error,
×
212
                "thread::join", "hpx::thread: trying joining itself");
213
            return;
214
        }
215
        this_thread::interruption_point();
1,134✔
216

217
        // register callback function to be called when thread exits
218
        if (threads::add_thread_exit_callback(id_.noref(),
2,268✔
219
                hpx::bind_front(&resume_thread, HPX_MOVE(this_id))))
1,134✔
220
        {
221
            // wait for thread to be terminated
222
            unlock_guard ul(l);
381✔
223
            this_thread::suspend(
381✔
224
                threads::thread_schedule_state::suspended, "thread::join");
381✔
225
        }
381✔
226

227
        detach_locked();    // invalidate this object
1,134✔
228
    }
1,136✔
229

230
    // extensions
231
    void thread::interrupt(bool flag)
4✔
232
    {
233
        threads::interrupt_thread(native_handle(), flag);
4✔
234
    }
4✔
235

236
    bool thread::interruption_requested() const
×
237
    {
238
        return threads::get_thread_interruption_requested(native_handle());
×
239
    }
240

241
    void thread::interrupt(thread::id id, bool flag)
2✔
242
    {
243
        threads::interrupt_thread(id.id_, flag);
2✔
244
    }
2✔
245

246
    std::size_t thread::get_thread_data() const
×
247
    {
248
        return threads::get_thread_data(native_handle());
×
249
    }
250
    std::size_t thread::set_thread_data(std::size_t data)
×
251
    {
252
        return threads::set_thread_data(native_handle(), data);
×
253
    }
254

255
#if defined(HPX_HAVE_LIBCDS)
256
    std::size_t thread::get_libcds_data() const
257
    {
258
        return threads::get_libcds_data(native_handle());
259
    }
260
    std::size_t thread::set_libcds_data(std::size_t data)
261
    {
262
        return threads::set_libcds_data(native_handle(), data);
263
    }
264

265
    std::size_t thread::get_libcds_hazard_pointer_data() const
266
    {
267
        return threads::get_libcds_hazard_pointer_data(native_handle());
268
    }
269
    std::size_t thread::set_libcds_hazard_pointer_data(std::size_t data)
270
    {
271
        return threads::set_libcds_hazard_pointer_data(native_handle(), data);
272
    }
273

274
    std::size_t thread::get_libcds_dynamic_hazard_pointer_data() const
275
    {
276
        return threads::get_libcds_dynamic_hazard_pointer_data(native_handle());
277
    }
278
    std::size_t thread::set_libcds_dynamic_hazard_pointer_data(std::size_t data)
279
    {
280
        return threads::set_libcds_dynamic_hazard_pointer_data(
281
            native_handle(), data);
282
    }
283
#endif
284

285
    ///////////////////////////////////////////////////////////////////////////
286
    namespace detail {
287
        struct thread_task_base : lcos::detail::future_data<void>
×
288
        {
289
        private:
290
            typedef hpx::intrusive_ptr<thread_task_base> future_base_type;
291

292
        protected:
293
            using base_type = lcos::detail::future_data<void>;
294
            using result_type = base_type::result_type;
295

296
            using base_type::mtx_;
297

298
        public:
299
            thread_task_base(threads::thread_id_ref_type const& id)
×
300
            {
×
301
                if (threads::add_thread_exit_callback(id.noref(),
×
302
                        hpx::bind_front(&thread_task_base::thread_exit_function,
×
303
                            future_base_type(this))))
×
304
                {
305
                    id_ = id;
×
306
                }
×
307
            }
×
308

309
            bool valid() const noexcept
×
310
            {
311
                return id_ != threads::invalid_thread_id;
×
312
            }
313

314
            // cancellation support
315
            bool cancelable() const noexcept override
×
316
            {
317
                return true;
×
318
            }
319

320
            void cancel() override
×
321
            {
322
                std::lock_guard l(mtx_);
×
323
                if (!this->is_ready())
×
324
                {
325
                    threads::interrupt_thread(id_.noref());
×
326
                    this->set_error(hpx::error::thread_cancelled,
×
327
                        "thread_task_base::cancel", "future has been canceled");
328
                    id_ = threads::invalid_thread_id;
×
329
                }
×
330
            }
×
331

332
        protected:
333
            void thread_exit_function()
×
334
            {
335
                // might have been finished or canceled
336
                std::lock_guard l(mtx_);
×
337
                if (!this->is_ready())
×
338
                    this->set_data(result_type());
×
339
                id_ = threads::invalid_thread_id;
×
340
            }
×
341

342
        private:
343
            threads::thread_id_ref_type id_;
344
        };
345
    }    // namespace detail
346

347
    hpx::future<void> thread::get_future(error_code& ec)
×
348
    {
349
        if (id_ == threads::invalid_thread_id)
×
350
        {
351
            HPX_THROWS_IF(ec, hpx::error::null_thread_id, "thread::get_future",
×
352
                "null thread id encountered");
353
            return hpx::future<void>();
×
354
        }
355

356
        detail::thread_task_base* p = new detail::thread_task_base(id_);
×
357
        hpx::intrusive_ptr<lcos::detail::future_data<void>> base(p);
×
358
        if (!p->valid())
×
359
        {
360
            HPX_THROWS_IF(ec, hpx::error::thread_resource_error,
×
361
                "thread::get_future",
362
                "Could not create future as thread has been terminated.");
363
            return hpx::future<void>();
×
364
        }
365

366
        using traits::future_access;
367
        return future_access<hpx::future<void>>::create(HPX_MOVE(base));
×
368
    }
×
369

370
    ///////////////////////////////////////////////////////////////////////////
371
    namespace this_thread {
372

373
        void yield_to(thread::id id) noexcept
2,526✔
374
        {
375
            this_thread::suspend(threads::thread_schedule_state::pending,
2,526✔
376
                id.native_handle(), "this_thread::yield_to");
2,526✔
377
        }
2,526✔
378

379
        void yield() noexcept
1,639,227✔
380
        {
381
            this_thread::suspend(
1,639,227✔
382
                threads::thread_schedule_state::pending, "this_thread::yield");
1,639,227✔
383
        }
1,639,345✔
384

385
        thread::id get_id() noexcept
14,463✔
386
        {
387
            return thread::id(threads::get_self_id());
14,463✔
388
        }
389

390
        // extensions
391
        threads::thread_priority get_priority()
18✔
392
        {
393
            return threads::get_thread_priority(threads::get_self_id());
18✔
394
        }
395

396
        std::ptrdiff_t get_stack_size()
1,584,580✔
397
        {
398
            return threads::get_stack_size(threads::get_self_id());
1,584,580✔
399
        }
400

401
        void interruption_point()
1,136✔
402
        {
403
            threads::interruption_point(threads::get_self_id());
1,136✔
404
        }
1,136✔
405

406
        bool interruption_enabled()
1✔
407
        {
408
            return threads::get_thread_interruption_enabled(
1✔
409
                threads::get_self_id());
1✔
410
        }
411

412
        bool interruption_requested()
×
413
        {
414
            return threads::get_thread_interruption_requested(
×
415
                threads::get_self_id());
×
416
        }
417

418
        void interrupt()
×
419
        {
420
            threads::interrupt_thread(threads::get_self_id());
×
421
            threads::interruption_point(threads::get_self_id());
×
422
        }
×
423

424
        void sleep_until(hpx::chrono::steady_time_point const& abs_time)
2,601✔
425
        {
426
            this_thread::suspend(abs_time, "this_thread::sleep_until");
2,601✔
427
        }
2,601✔
428

429
        std::size_t get_thread_data()
×
430
        {
431
            return threads::get_thread_data(threads::get_self_id());
×
432
        }
433

434
        std::size_t set_thread_data(std::size_t data)
×
435
        {
436
            return threads::set_thread_data(threads::get_self_id(), data);
×
437
        }
438

439
#if defined(HPX_HAVE_LIBCDS)
440
        std::size_t get_libcds_data()
441
        {
442
            return threads::get_libcds_data(threads::get_self_id());
443
        }
444

445
        std::size_t set_libcds_data(std::size_t data)
446
        {
447
            return threads::set_libcds_data(threads::get_self_id(), data);
448
        }
449

450
        std::size_t get_libcds_hazard_pointer_data()
451
        {
452
            return threads::get_libcds_hazard_pointer_data(
453
                threads::get_self_id());
454
        }
455

456
        std::size_t set_libcds_hazard_pointer_data(std::size_t data)
457
        {
458
            return threads::set_libcds_hazard_pointer_data(
459
                threads::get_self_id(), data);
460
        }
461

462
        std::size_t get_libcds_dynamic_hazard_pointer_data()
463
        {
464
            return threads::get_libcds_dynamic_hazard_pointer_data(
465
                threads::get_self_id());
466
        }
467

468
        std::size_t set_libcds_dynamic_hazard_pointer_data(std::size_t data)
469
        {
470
            return threads::set_libcds_dynamic_hazard_pointer_data(
471
                threads::get_self_id(), data);
472
        }
473
#endif
474
        ///////////////////////////////////////////////////////////////////////
475
        disable_interruption::disable_interruption()
1✔
476
          : interruption_was_enabled_(interruption_enabled())
1✔
477
        {
478
            if (interruption_was_enabled_)
1✔
479
            {
480
                interruption_was_enabled_ =
1✔
481
                    threads::set_thread_interruption_enabled(
1✔
482
                        threads::get_self_id(), false);
1✔
483
            }
1✔
484
        }
1✔
485

486
        disable_interruption::~disable_interruption()
1✔
487
        {
488
            threads::thread_self* p = threads::get_self_ptr();
1✔
489
            if (p)
1✔
490
            {
491
                threads::set_thread_interruption_enabled(
1✔
492
                    threads::get_self_id(), interruption_was_enabled_);
1✔
493
            }
1✔
494
        }
1✔
495

496
        ///////////////////////////////////////////////////////////////////////
497
        restore_interruption::restore_interruption(disable_interruption& d)
×
498
          : interruption_was_enabled_(d.interruption_was_enabled_)
×
499
        {
500
            if (!interruption_was_enabled_)
×
501
            {
502
                interruption_was_enabled_ =
×
503
                    threads::set_thread_interruption_enabled(
×
504
                        threads::get_self_id(), true);
×
505
            }
×
506
        }
×
507

508
        restore_interruption::~restore_interruption()
×
509
        {
510
            threads::thread_self* p = threads::get_self_ptr();
×
511
            if (p)
×
512
            {
513
                threads::set_thread_interruption_enabled(
×
514
                    threads::get_self_id(), interruption_was_enabled_);
×
515
            }
×
516
        }
×
517
    }    // namespace this_thread
518
}    // namespace hpx
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