• 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

47.85
/libs/core/threading_base/src/thread_helpers.cpp
1
//  Copyright (c) 2007-2025 Hartmut Kaiser
2
//  Copyright (c)      2011 Bryce Lelbach
3
//
4
//  SPDX-License-Identifier: BSL-1.0
5
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
6
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7

8
#include <hpx/assert.hpp>
9
#include <hpx/modules/coroutines.hpp>
10
#include <hpx/modules/errors.hpp>
11
#include <hpx/modules/execution_base.hpp>
12
#include <hpx/modules/timing.hpp>
13
#include <hpx/threading_base/scheduler_base.hpp>
14
#include <hpx/threading_base/scheduler_state.hpp>
15
#include <hpx/threading_base/set_thread_state.hpp>
16
#include <hpx/threading_base/set_thread_state_timed.hpp>
17
#include <hpx/threading_base/thread_description.hpp>
18
#include <hpx/threading_base/thread_helpers.hpp>
19
#include <hpx/threading_base/thread_pool_base.hpp>
20

21
#ifdef HPX_HAVE_VERIFY_LOCKS
22
#include <hpx/modules/lock_registration.hpp>
23
#endif
24
#ifdef HPX_HAVE_THREAD_DESCRIPTION
25
#include <hpx/threading_base/detail/reset_lco_description.hpp>
26
#endif
27
#ifdef HPX_HAVE_THREAD_BACKTRACE_ON_SUSPENSION
28
#include <hpx/modules/debugging.hpp>
29
#include <hpx/threading_base/detail/reset_backtrace.hpp>
30
#endif
31

32
#include <atomic>
33
#include <cstddef>
34
#include <limits>
35
#include <memory>
36
#include <utility>
37

38
///////////////////////////////////////////////////////////////////////////////
39
namespace hpx::threads {
40

41
    ///////////////////////////////////////////////////////////////////////////
42
    thread_state set_thread_state(thread_id_type const& id,
43
        thread_schedule_state state, thread_restart_state stateex,
54✔
44
        thread_priority priority, bool retry_on_active, error_code& ec)
45
    {
46
        if (&ec != &throws)
47
            ec = make_success_code();
54✔
48

×
49
        return detail::set_thread_state(id, state, stateex, priority,
50
            thread_schedule_hint(), retry_on_active, ec);
54✔
51
    }
54✔
52

53
    ///////////////////////////////////////////////////////////////////////////
54
    thread_id_ref_type set_thread_state(thread_id_type const& id,
55
        hpx::chrono::steady_time_point const& abs_time,
141✔
56
        std::atomic<bool>* timer_started, thread_schedule_state state,
57
        thread_restart_state stateex, thread_priority priority,
58
        bool retry_on_active, error_code& ec)
59
    {
60
        return detail::set_thread_state_timed(
61
            get_thread_id_data(id)->get_scheduler_base(), abs_time, id, state,
62
            stateex, priority, thread_schedule_hint(), timer_started,
63
            retry_on_active, ec);
64
    }
141✔
65

66
    ///////////////////////////////////////////////////////////////////////////
67
    thread_state get_thread_state(
68
        thread_id_type const& id, error_code& /* ec */) noexcept
6✔
69
    {
70
        return id ? get_thread_id_data(id)->get_state() :
71
                    thread_state(thread_schedule_state::terminated,
6✔
72
                        thread_restart_state::unknown);
73
    }
6✔
74

75
    ///////////////////////////////////////////////////////////////////////////
76
    std::size_t get_thread_phase(
77
        thread_id_type const& id, error_code& /* ec */) noexcept
×
78
    {
79
        return id ? get_thread_id_data(id)->get_thread_phase() :
80
                    static_cast<std::size_t>(~0);
×
81
    }
×
82

83
    ///////////////////////////////////////////////////////////////////////////
84
    threads::thread_priority get_thread_priority(
85
        thread_id_type const& id, error_code& /* ec */) noexcept
3✔
86
    {
87
        return id ? get_thread_id_data(id)->get_priority() :
88
                    thread_priority::unknown;
3✔
89
    }
3✔
90

91
    std::ptrdiff_t get_stack_size(
92
        thread_id_type const& id, error_code& /* ec */) noexcept
41,751✔
93
    {
94
        return id ? get_thread_id_data(id)->get_stack_size() :
95
                    static_cast<std::ptrdiff_t>(thread_stacksize::unknown);
41,751✔
96
    }
41,751✔
97

98
    void interrupt_thread(thread_id_type const& id, bool flag, error_code& ec)
99
    {
×
100
        if (HPX_UNLIKELY(!id))
101
        {
×
102
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
103
                "hpx::threads::interrupt_thread", "null thread id encountered");
×
104
            return;
105
        }
×
106

107
        if (&ec != &throws)
108
            ec = make_success_code();
×
109

×
110
        get_thread_id_data(id)->interrupt(flag);    // notify thread
111

×
112
        // Set thread state to pending. If the thread is currently active we do
113
        // not retry. The thread will either exit or hit an interruption_point.
114
        set_thread_state(id, thread_schedule_state::pending,
115
            thread_restart_state::abort, thread_priority::normal, false, ec);
×
116
    }
117

118
    void interruption_point(thread_id_type const& id, error_code& ec)
119
    {
2,145,762✔
120
        if (HPX_UNLIKELY(!id))
121
        {
2,145,762✔
122
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
123
                "hpx::threads::interruption_point",
×
124
                "null thread id encountered");
125
            return;
126
        }
×
127

128
        if (&ec != &throws)
129
            ec = make_success_code();
2,145,762✔
130

×
131
        get_thread_id_data(id)->interruption_point();    // notify thread
132
    }
2,145,762✔
133

134
    ///////////////////////////////////////////////////////////////////////////
135
    bool get_thread_interruption_enabled(
136
        thread_id_type const& id, error_code& ec)
×
137
    {
138
        if (HPX_UNLIKELY(!id))
139
        {
×
140
            HPX_THROW_EXCEPTION(hpx::error::null_thread_id,
141
                "hpx::threads::get_thread_interruption_enabled",
×
142
                "null thread id encountered");
143
        }
144

145
        if (&ec != &throws)
146
            ec = make_success_code();
×
147

×
148
        return get_thread_id_data(id)->interruption_enabled();
149
    }
×
150

151
    bool set_thread_interruption_enabled(
152
        thread_id_type const& id, bool enable, error_code& ec)
×
153
    {
154
        if (HPX_UNLIKELY(!id))
155
        {
×
156
            HPX_THROW_EXCEPTION(hpx::error::null_thread_id,
157
                "hpx::threads::get_thread_interruption_enabled",
×
158
                "null thread id encountered");
159
        }
160

161
        if (&ec != &throws)
162
            ec = make_success_code();
×
163

×
164
        return get_thread_id_data(id)->set_interruption_enabled(enable);
165
    }
×
166

167
    bool get_thread_interruption_requested(
168
        thread_id_type const& id, error_code& ec)
×
169
    {
170
        if (HPX_UNLIKELY(!id))
171
        {
×
172
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
173
                "hpx::threads::get_thread_interruption_requested",
×
174
                "null thread id encountered");
175
            return false;
176
        }
×
177

178
        if (&ec != &throws)
179
            ec = make_success_code();
×
180

×
181
        return get_thread_id_data(id)->interruption_requested();
182
    }
×
183

184
    ///////////////////////////////////////////////////////////////////////////
185
    std::size_t get_thread_data(thread_id_type const& id, error_code& ec)
186
    {
×
187
        if (HPX_UNLIKELY(!id))
188
        {
×
189
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
190
                "hpx::threads::get_thread_data", "null thread id encountered");
×
191
            return 0;
192
        }
×
193

194
        return get_thread_id_data(id)->get_thread_data();
195
    }
×
196

197
    std::size_t set_thread_data(
198
        thread_id_type const& id, std::size_t data, error_code& ec)
×
199
    {
200
        if (HPX_UNLIKELY(!id))
201
        {
×
202
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
203
                "hpx::threads::set_thread_data", "null thread id encountered");
×
204
            return 0;
205
        }
×
206

207
        return get_thread_id_data(id)->set_thread_data(data);
208
    }
×
209

210
#if defined(HPX_HAVE_LIBCDS)
211
    std::size_t get_libcds_data(thread_id_type const& id, error_code& ec)
212
    {
213
        if (HPX_UNLIKELY(!id))
214
        {
215
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
216
                "hpx::threads::get_libcds_data", "null thread id encountered");
217
            return 0;
218
        }
219

220
        return get_thread_id_data(id)->get_libcds_data();
221
    }
222

223
    std::size_t set_libcds_data(
224
        thread_id_type const& id, std::size_t data, error_code& ec)
225
    {
226
        if (HPX_UNLIKELY(!id))
227
        {
228
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
229
                "hpx::threads::set_libcds_data", "null thread id encountered");
230
            return 0;
231
        }
232

233
        return get_thread_id_data(id)->set_libcds_data(data);
234
    }
235

236
    std::size_t get_libcds_hazard_pointer_data(
237
        thread_id_type const& id, error_code& ec)
238
    {
239
        if (HPX_UNLIKELY(!id))
240
        {
241
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
242
                "hpx::threads::get_libcds_hazard_pointer_data",
243
                "null thread id encountered");
244
            return 0;
245
        }
246

247
        return get_thread_id_data(id)->get_libcds_hazard_pointer_data();
248
    }
249

250
    std::size_t set_libcds_hazard_pointer_data(
251
        thread_id_type const& id, std::size_t data, error_code& ec)
252
    {
253
        if (HPX_UNLIKELY(!id))
254
        {
255
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
256
                "hpx::threads::set_libcds_hazard_pointer_data",
257
                "null thread id encountered");
258
            return 0;
259
        }
260

261
        return get_thread_id_data(id)->set_libcds_hazard_pointer_data(data);
262
    }
263

264
    std::size_t get_libcds_dynamic_hazard_pointer_data(
265
        thread_id_type const& id, error_code& ec)
266
    {
267
        if (HPX_UNLIKELY(!id))
268
        {
269
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
270
                "hpx::threads::get_libcds_dynamic_hazard_pointer_data",
271
                "null thread id encountered");
272
            return 0;
273
        }
274

275
        return get_thread_id_data(id)->get_libcds_dynamic_hazard_pointer_data();
276
    }
277

278
    std::size_t set_libcds_dynamic_hazard_pointer_data(
279
        thread_id_type const& id, std::size_t data, error_code& ec)
280
    {
281
        if (HPX_UNLIKELY(!id))
282
        {
283
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
284
                "hpx::threads::set_libcds_dynamic_hazard_pointer_data",
285
                "null thread id encountered");
286
            return 0;
287
        }
288

289
        return get_thread_id_data(id)->set_libcds_dynamic_hazard_pointer_data(
290
            data);
291
    }
292

293
#endif
294

295
    ////////////////////////////////////////////////////////////////////////////
296
    namespace {
297

298
        thread_local std::size_t continuation_recursion_count(0);
299
    }
×
300

301
    std::size_t& get_continuation_recursion_count() noexcept
×
302
    {
303
        if (thread_self* self_ptr = get_self_ptr())
×
304
        {
305
            return self_ptr->get_continuation_recursion_count();
306
        }
307
        return continuation_recursion_count;
308
    }
471✔
309

310
    void reset_continuation_recursion_count() noexcept
471✔
311
    {
471✔
312
        continuation_recursion_count = 0;
313
    }
314

12✔
315
    ///////////////////////////////////////////////////////////////////////////
316
    void run_thread_exit_callbacks(thread_id_type const& id, error_code& ec)
12✔
317
    {
318
        if (HPX_UNLIKELY(!id))
×
319
        {
320
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
321
                "hpx::threads::run_thread_exit_callbacks",
×
322
                "null thread id encountered");
323
            return;
324
        }
12✔
325

×
326
        if (&ec != &throws)
327
            ec = make_success_code();
12✔
328

329
        get_thread_id_data(id)->run_thread_exit_callbacks();
330
    }
12✔
331

332
    bool add_thread_exit_callback(thread_id_type const& id,
333
        hpx::function<void()> const& f, error_code& ec)
12✔
334
    {
335
        if (HPX_UNLIKELY(!id))
×
336
        {
337
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
338
                "hpx::threads::add_thread_exit_callback",
×
339
                "null thread id encountered");
340
            return false;
341
        }
12✔
342

×
343
        if (&ec != &throws)
344
            ec = make_success_code();
12✔
345

346
        return get_thread_id_data(id)->add_thread_exit_callback(f);
347
    }
12✔
348

349
    void free_thread_exit_callbacks(thread_id_type const& id, error_code& ec)
12✔
350
    {
351
        if (HPX_UNLIKELY(!id))
×
352
        {
353
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
354
                "hpx::threads::add_thread_exit_callback",
×
355
                "null thread id encountered");
356
            return;
357
        }
12✔
358

×
359
        if (&ec != &throws)
360
            ec = make_success_code();
12✔
361

362
        get_thread_id_data(id)->free_thread_exit_callbacks();
363
    }
364

365
    ///////////////////////////////////////////////////////////////////////////
366
#ifdef HPX_HAVE_THREAD_FULLBACKTRACE_ON_SUSPENSION
367
    char const* get_thread_backtrace(thread_id_type const& id, error_code& ec)
×
368
#else
369
    util::backtrace const* get_thread_backtrace(
370
        thread_id_type const& id, error_code& ec)
371
#endif
×
372
    {
373
        if (HPX_UNLIKELY(!id))
×
374
        {
375
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
376
                "hpx::threads::get_thread_backtrace",
×
377
                "null thread id encountered");
378
            return nullptr;
379
        }
×
380

×
381
        if (&ec != &throws)
382
            ec = make_success_code();
×
383

384
        return get_thread_id_data(id)->get_backtrace();
385
    }
386

387
#ifdef HPX_HAVE_THREAD_FULLBACKTRACE_ON_SUSPENSION
388
    char const* set_thread_backtrace(
389
        thread_id_type const& id, char const* bt, error_code& ec)
×
390
#else
391
    util::backtrace const* set_thread_backtrace(
392
        thread_id_type const& id, util::backtrace const* bt, error_code& ec)
393
#endif
×
394
    {
395
        if (HPX_UNLIKELY(!id))
×
396
        {
397
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
398
                "hpx::threads::set_thread_backtrace",
×
399
                "null thread id encountered");
400
            return nullptr;
401
        }
×
402

×
403
        if (&ec != &throws)
404
            ec = make_success_code();
×
405

406
        return get_thread_id_data(id)->set_backtrace(bt);
407
    }
1,097✔
408

409
    threads::thread_pool_base* get_pool(
410
        thread_id_type const& id, error_code& ec)
1,097✔
411
    {
412
        if (HPX_UNLIKELY(!id))
×
413
        {
414
            HPX_THROWS_IF(ec, hpx::error::null_thread_id,
×
415
                "hpx::threads::get_pool", "null thread id encountered");
416
            return nullptr;
417
        }
1,097✔
418

×
419
        if (&ec != &throws)
420
            ec = make_success_code();
1,097✔
421

422
        return get_thread_id_data(id)->get_scheduler_base()->get_parent_pool();
423
    }
424
}    // namespace hpx::threads
425

426
namespace hpx::this_thread {
427

428
    // The function 'suspend' will return control to the thread manager
429
    // (suspends the current thread). It sets the new state of this thread to
430
    // the thread state passed as the parameter.
431
    //
432
    // If the suspension was aborted, this function will throw a
1,072,746✔
433
    // \a yield_aborted exception.
434
    threads::thread_restart_state suspend(threads::thread_schedule_state state,
435
        threads::thread_id_type nextid,
436
        [[maybe_unused]] threads::thread_description const& description,
437
        error_code& ec)
438
    {
1,072,746✔
439
        // let the thread manager do other things while waiting
440
        threads::thread_self& self = threads::get_self();
441

2,145,492✔
442
        // keep alive
443
        threads::thread_id_ref_type id = self.get_outer_thread_id();
444

1,072,746✔
445
        // handle interruption, if needed
1,072,746✔
446
        threads::interruption_point(id.noref(), ec);
447
        if (ec)
448
            return threads::thread_restart_state::unknown;
449

450
        threads::thread_restart_state statex;
451

452
        {
453
#ifdef HPX_HAVE_VERIFY_LOCKS
454
            // verify that there are no more registered locks for this OS-thread
455
            util::verify_no_locks();
456

457
            [[maybe_unused]] auto held_locks = hpx::experimental::scope_exit(
458
                [data = hpx::util::get_held_locks_data()]() mutable {
459
                    hpx::util::set_held_locks_data(HPX_MOVE(data));
460
                });
461
#endif
462
#ifdef HPX_HAVE_THREAD_DESCRIPTION
463
            threads::detail::reset_lco_description desc(
464
                id.noref(), description, ec);
1,072,746✔
465
#endif
466
#ifdef HPX_HAVE_THREAD_BACKTRACE_ON_SUSPENSION
467
            threads::detail::reset_backtrace bt(id, ec);
468
#endif
469

470
            // We might need to dispatch 'nextid' to it's correct scheduler only
×
471
            // if our current scheduler is the same, we should yield to the id
472
            if (nextid &&
473
                get_thread_id_data(nextid)->get_scheduler_base() !=
×
474
                    get_thread_id_data(id)->get_scheduler_base())
475
            {
476
                auto* scheduler =
477
                    get_thread_id_data(nextid)->get_scheduler_base();
478
                scheduler->schedule_thread(
1,072,746✔
479
                    HPX_MOVE(nextid), threads::thread_schedule_hint());
1,072,746✔
480

481
                statex = self.yield(threads::thread_result_type(
482
                    state, threads::invalid_thread_id));
483
            }
484
            else
1,072,746✔
485
            {
1,072,746✔
486
                statex = self.yield(
487
                    threads::thread_result_type(state, HPX_MOVE(nextid)));
488
            }
489
        }
1,072,746✔
490

491
        // handle interruption, if needed
×
492
        threads::interruption_point(id.noref(), ec);
493
        if (ec)
494
            return threads::thread_restart_state::unknown;
495

496
        // handle interrupt and abort
1,072,746✔
497
        if (statex == threads::thread_restart_state::abort)
×
498
        {
499
            HPX_THROWS_IF(ec, hpx::error::yield_aborted, "suspend",
500
                "thread({}, {}) aborted (yield returned wait_abort)",
501
                id.noref(), threads::get_thread_description(id.noref()));
502
        }
129✔
503

504
        if (&ec != &throws)
505
            ec = make_success_code();
506

507
        return statex;
508
    }
509

129✔
510
    threads::thread_restart_state suspend(
511
        hpx::chrono::steady_time_point const& abs_time,
512
        threads::thread_id_type nextid,
258✔
513
        [[maybe_unused]] threads::thread_description const& description,
514
        error_code& ec)
515
    {
129✔
516
        // schedule a thread waking us up at_time
129✔
517
        threads::thread_self& self = threads::get_self();
518

519
        // keep alive
520
        threads::thread_id_ref_type id = self.get_outer_thread_id();
521

522
        // handle interruption, if needed
523
        threads::interruption_point(id.noref(), ec);
524
        if (ec)
525
            return threads::thread_restart_state::unknown;
526

527
        // let the thread manager do other things while waiting
528
        threads::thread_restart_state statex;
529

530
        {
531
#ifdef HPX_HAVE_VERIFY_LOCKS
532
            // verify that there are no more registered locks for this OS-thread
533
            util::verify_no_locks();
534

129✔
535
            [[maybe_unused]] auto held_locks = hpx::experimental::scope_exit(
536
                [data = hpx::util::get_held_locks_data()]() mutable {
129✔
537
                    hpx::util::set_held_locks_data(HPX_MOVE(data));
538
                });
539
#endif
129✔
540
#ifdef HPX_HAVE_THREAD_DESCRIPTION
129✔
541
            threads::detail::reset_lco_description desc(
542
                id.noref(), description, ec);
543
#endif
544
#ifdef HPX_HAVE_THREAD_BACKTRACE_ON_SUSPENSION
545
            threads::detail::reset_backtrace bt(id, ec);
129✔
546
#endif
547

548
            std::atomic<bool> timer_started(false);
549
            threads::thread_id_ref_type const timer_id =
550
                threads::set_thread_state(id.noref(), abs_time, &timer_started,
551
                    threads::thread_schedule_state::pending,
×
552
                    threads::thread_restart_state::timeout,
553
                    threads::thread_priority::boost, true, ec);
554
            if (ec)
×
555
                return threads::thread_restart_state::unknown;
556

557
            // We might need to dispatch 'nextid' to it's correct scheduler only
558
            // if our current scheduler is the same, we should yield to the id
559
            if (nextid &&
560
                get_thread_id_data(nextid)->get_scheduler_base() !=
129✔
561
                    get_thread_id_data(id)->get_scheduler_base())
562
            {
563
                auto* scheduler =
564
                    get_thread_id_data(nextid)->get_scheduler_base();
565
                scheduler->schedule_thread(
129✔
566
                    HPX_MOVE(nextid), threads::thread_schedule_hint());
567

568
                statex = self.yield(threads::thread_result_type(
569
                    threads::thread_schedule_state::suspended,
570
                    threads::invalid_thread_id));
571
            }
×
572
            else
×
573
            {
574
                statex = self.yield(threads::thread_result_type(
×
575
                    threads::thread_schedule_state::suspended,
576
                    HPX_MOVE(nextid)));
577
            }
578

579
            if (statex != threads::thread_restart_state::timeout)
580
            {
581
                HPX_ASSERT(statex == threads::thread_restart_state::abort ||
582
                    statex == threads::thread_restart_state::signaled);
129✔
583

129✔
584
                error_code ec1(throwmode::lightweight);    // do not throw
585
                hpx::util::yield_while<true>(
586
                    [&timer_started]() { return !timer_started.load(); },
587
                    "set_thread_state_timed");
129✔
588
                threads::set_thread_state(timer_id.noref(),
589
                    threads::thread_schedule_state::pending,
×
590
                    threads::thread_restart_state::abort,
591
                    threads::thread_priority::boost, true, ec1);
592
            }
593
        }
594

129✔
595
        // handle interruption, if needed
×
596
        threads::interruption_point(id.noref(), ec);
597
        if (ec)
598
            return threads::thread_restart_state::unknown;
599

600
        // handle interrupt and abort
601
        if (statex == threads::thread_restart_state::abort)
1,097✔
602
        {
603
            HPX_THROWS_IF(ec, hpx::error::yield_aborted, "suspend_at",
1,097✔
604
                "thread({}, {}) aborted (yield returned wait_abort)",
605
                id.noref(), threads::get_thread_description(id.noref()));
606
        }
125,712✔
607

608
        if (&ec != &throws)
125,712✔
609
            ec = make_success_code();
610

125,712✔
611
        return statex;
612
    }
613

614
    ///////////////////////////////////////////////////////////////////////////
615
    threads::thread_pool_base* get_pool(error_code& ec)
125,787✔
616
    {
617
        return threads::get_pool(threads::get_self_id(), ec);
618
    }
125,787✔
619

620
    std::ptrdiff_t get_available_stack_space() noexcept
621
    {
622
        if (threads::thread_self const* self = threads::get_self_ptr())
125,712✔
623
        {
125,712✔
624
            return self->get_available_stack_space();
625
        }
×
626
        return (std::numeric_limits<std::ptrdiff_t>::max)();
627
    }
628

125,712✔
629
    bool has_sufficient_stack_space(
125,712✔
630
        [[maybe_unused]] std::size_t space_needed) noexcept
631
    {
125,712✔
632
        if (nullptr == hpx::threads::get_self_ptr())
633
            return false;
634

635
#if defined(HPX_HAVE_THREADS_GET_STACK_POINTER)
636
        std::ptrdiff_t const remaining_stack = get_available_stack_space();
637
        if (remaining_stack < 0)
638
        {
639
            HPX_THROW_BAD_ALLOC("has_sufficient_stack_space");
640
        }
641
        bool const sufficient_stack_space =
642
            static_cast<std::size_t>(remaining_stack) >= space_needed;
643

644
        return sufficient_stack_space;
645
#else
646
        return true;
647
#endif
648
    }
649
}    // namespace hpx::this_thread
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