• 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

54.42
/libs/core/runtime_local/src/runtime_local.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/config.hpp>
9
#include <hpx/assert.hpp>
10
#include <hpx/itt_notify/thread_name.hpp>
11
#include <hpx/modules/command_line_handling_local.hpp>
12
#include <hpx/modules/coroutines.hpp>
13
#include <hpx/modules/debugging.hpp>
14
#include <hpx/modules/errors.hpp>
15
#include <hpx/modules/execution_base.hpp>
16
#include <hpx/modules/format.hpp>
17
#include <hpx/modules/functional.hpp>
18
#include <hpx/modules/io_service.hpp>
19
#include <hpx/modules/logging.hpp>
20
#include <hpx/modules/static_reinit.hpp>
21
#include <hpx/modules/thread_support.hpp>
22
#include <hpx/modules/threading_base.hpp>
23
#include <hpx/modules/threadmanager.hpp>
24
#include <hpx/modules/timing.hpp>
25
#include <hpx/modules/topology.hpp>
26
#include <hpx/modules/type_support.hpp>
27
#include <hpx/modules/util.hpp>
28
#include <hpx/runtime_local/config_entry.hpp>
29
#include <hpx/runtime_local/custom_exception_info.hpp>
30
#include <hpx/runtime_local/debugging.hpp>
31
#include <hpx/runtime_local/os_thread_type.hpp>
32
#include <hpx/runtime_local/runtime_local.hpp>
33
#include <hpx/runtime_local/runtime_local_fwd.hpp>
34
#include <hpx/runtime_local/shutdown_function.hpp>
35
#include <hpx/runtime_local/startup_function.hpp>
36
#include <hpx/runtime_local/state.hpp>
37
#include <hpx/runtime_local/thread_hooks.hpp>
38
#include <hpx/runtime_local/thread_mapper.hpp>
39
#include <hpx/version.hpp>
40

41
#include <atomic>
42
#include <condition_variable>
43
#include <csignal>
44
#include <cstddef>
45
#include <cstdint>
46
#include <cstring>
47
#include <exception>
48
#include <functional>
49
#include <iomanip>
50
#include <iostream>
51
#include <list>
52
#include <memory>
53
#include <mutex>
54
#include <sstream>
55
#include <string>
56
#include <thread>
57
#include <utility>
58

59
#if defined(HPX_HAVE_LOGGING)
60
namespace hpx::detail {
61

62
    void try_log_runtime_threads()
63
    {
64
        // This may be used in non-valid runtime states, let it fail silently
65
        try
66
        {
67
            auto rt = hpx::get_runtime_ptr();
68
            if (rt == nullptr)
69
                return;
70

71
            [[maybe_unused]] auto ret =
72
                rt->get_thread_manager().enumerate_threads(
73
                    [](hpx::threads::thread_id_type const& id) -> bool {
74
                        hpx::threads::thread_data* td = get_thread_id_data(id);
75
                        auto sched = td->get_scheduler_base();
76
                        LTM_(debug).format(
77
                            "Logging all runtime threads: pool({}), "
78
                            "scheduler({}),"
79
                            "thread({}), description({}), state({})",
80
                            sched->get_parent_pool(), sched, id,
81
                            td->get_description(), td->get_state().state());
82
                        return true;
83
                    });
84
        }
85
        // NOLINTNEXTLINE(bugprone-empty-catch)
86
        catch (...)
87
        {
88
        }
89
    }
90
}    // namespace hpx::detail
91
#endif
92

93
///////////////////////////////////////////////////////////////////////////////
94
// Make sure the system gets properly shut down while handling Ctrl-C and other
95
// system signals
96
#if defined(HPX_WINDOWS)
97

98
namespace hpx {
99

100
    ///////////////////////////////////////////////////////////////////////////
101
    void handle_termination(char const* reason)
102
    {
103
        if (hpx::threads::coroutines::attach_debugger_on_sigv)
104
        {
105
            util::attach_debugger();
106
        }
107

108
        if (hpx::threads::coroutines::diagnostics_on_terminate)
109
        {
110
            int const verbosity = hpx::threads::coroutines::exception_verbosity;
111

112
            if (verbosity >= 2)
113
            {
114
                std::cerr << full_build_string() << "\n" << std::flush;
115
            }
116

117
#if defined(HPX_HAVE_STACKTRACES)
118
            if (verbosity >= 1)
119
            {
120
                std::size_t const trace_depth =
121
                    util::from_string<std::size_t>(get_config_entry(
122
                        "hpx.trace_depth", HPX_HAVE_THREAD_BACKTRACE_DEPTH));
123
                std::cerr << "{stack-trace}: " << hpx::util::trace(trace_depth)
124
                          << "\n"
125
                          << std::flush;
126
            }
127
#endif
128

129
#if defined(HPX_HAVE_LOGGING)
130
            LRT_(debug).format("Terminating due to system signal({})", reason);
131
            hpx::detail::try_log_runtime_threads();
132
#endif
133

134
            std::cerr << "{what}: " << (reason ? reason : "Unknown reason")
135
                      << "\n"
136
                      << std::flush;
137
        }
138
    }
×
139

140
    HPX_CORE_EXPORT BOOL WINAPI termination_handler(DWORD ctrl_type)
×
141
    {
142
        switch (ctrl_type)
143
        {
×
144
        case CTRL_C_EVENT:
145
            handle_termination("Ctrl-C");
146
            break;
×
147

148
        case CTRL_BREAK_EVENT:
×
149
            handle_termination("Ctrl-Break");
×
150
            break;
151

×
152
        case CTRL_CLOSE_EVENT:
153
            handle_termination("Ctrl-Close");
×
154
            break;
155

156
        case CTRL_LOGOFF_EVENT:
157
            handle_termination("Logoff");
×
158
            break;
159

160
        case CTRL_SHUTDOWN_EVENT:
×
161
            handle_termination("Shutdown");
162
            break;
×
163

×
164
        default:
165
            break;
166
        }
167
        return FALSE;
168
    }
×
169
}    // namespace hpx
170

×
171
#else
172

173
#include <signal.h>
174
#include <stdlib.h>
175
#include <string.h>
176

177
namespace hpx {
178

179
    ///////////////////////////////////////////////////////////////////////////
180
    [[noreturn]] HPX_CORE_EXPORT void termination_handler(int signum)
×
181
    {
182
        if (signum != SIGINT &&
×
183
            hpx::threads::coroutines::attach_debugger_on_sigv)
184
        {
185
            util::attach_debugger();
186
        }
187

188
        if (hpx::threads::coroutines::diagnostics_on_terminate)
189
        {
190
            int const verbosity = hpx::threads::coroutines::exception_verbosity;
191
            char* reason = strsignal(signum);
192

64✔
193
            if (verbosity >= 2)
194
            {
64✔
195
                std::cerr << full_build_string() << "\n" << std::flush;
64✔
196
            }
197

×
198
#if defined(HPX_HAVE_STACKTRACES)
199
            if (verbosity >= 1)
×
200
            {
×
201
                std::size_t const trace_depth =
202
                    util::from_string<std::size_t>(get_config_entry(
203
                        "hpx.trace_depth", HPX_HAVE_THREAD_BACKTRACE_DEPTH));
204
                std::cerr << "{stack-trace}: " << hpx::util::trace(trace_depth)
205
                          << "\n"
64✔
206
                          << std::flush;
207
            }
208
#endif
64✔
209

128✔
210
#if defined(HPX_HAVE_LOGGING)
64✔
211
            LRT_(debug).format("Terminating due to system signal({})", signum);
128✔
212
            hpx::detail::try_log_runtime_threads();
64✔
213
#endif
128✔
214

64✔
215
            std::cerr << "{what}: " << (reason ? reason : "Unknown reason")
216
                      << "\n"
64✔
217
                      << std::flush;
64✔
218
        }
219
        std::abort();
220
    }
221
}    // namespace hpx
222

223
#endif
224

225
///////////////////////////////////////////////////////////////////////////////
128✔
226
namespace hpx {
227

228
    ///////////////////////////////////////////////////////////////////////////
64✔
229
    [[noreturn]] HPX_CORE_EXPORT void HPX_CDECL new_handler()
64✔
230
    {
64✔
231
        HPX_THROW_BAD_ALLOC("new_handler");
232
    }
64✔
233

64✔
234
    ///////////////////////////////////////////////////////////////////////////
64✔
235
    namespace detail {
236

64✔
237
        namespace {
64✔
238

64✔
239
            // Sometimes the HPX library gets simply unloaded as a result of
64✔
240
            // some extreme error handling. Avoid hangs in the end by setting a
241
            // flag.
64✔
242
            bool exit_called = false;
243
        }    // namespace
244

245
        void on_exit() noexcept
×
246
        {
247
            exit_called = true;
248
        }
249

64✔
250
        void on_abort(int) noexcept
64✔
251
        {
252
            exit_called = true;
253
            std::abort();
254
        }
255
    }    // namespace detail
256

257
    ///////////////////////////////////////////////////////////////////////////
258
    void set_error_handlers(hpx::util::runtime_configuration const& cfg)
259
    {
260
        // initialize global variables
261
        hpx::threads::coroutines::attach_debugger_on_sigv =
262
            hpx::util::get_entry_as<std::string>(
263
                cfg, "hpx.attach_debugger", "") == "exception";
264
        hpx::threads::coroutines::diagnostics_on_terminate =
265
            hpx::util::get_entry_as<std::string>(
266
                cfg, "hpx.diagnostics_on_terminate", "1") == "1";
267
        hpx::threads::coroutines::exception_verbosity =
268
            hpx::util::get_entry_as<int>(cfg, "hpx.exception_verbosity", 2);
269
        hpx::threads::coroutines::exception_verbosity = 0;
270
#if defined(HPX_HAVE_STACKTRACES) && defined(HPX_HAVE_THREAD_BACKTRACE_DEPTH)
271
        hpx::threads::coroutines::exception_verbosity =
272
            hpx::util::get_entry_as<int>(
273
                cfg, "hpx.trace_depth", HPX_HAVE_THREAD_BACKTRACE_DEPTH);
5✔
274
#endif
275

5✔
276
#if defined(HPX_WINDOWS)
277
        if (hpx::util::get_entry_as<int>(cfg, "hpx.handle_signals", 1))
278
        {
279
            [[maybe_unused]] auto const prev_signal =
5✔
280
                std::signal(SIGABRT, detail::on_abort);
281
            HPX_ASSERT(prev_signal != SIG_ERR);
282
        }
283

284
        // Set console control handler to allow server to be stopped.
285
        SetConsoleCtrlHandler(hpx::termination_handler, TRUE);
286
#else
287
        if (hpx::util::get_entry_as<int>(cfg, "hpx.handle_signals", 1))
288
        {
289
            [[maybe_unused]] auto const prev_signal =
32✔
290
                std::signal(SIGABRT, detail::on_abort);
32✔
291
            HPX_ASSERT(prev_signal != SIG_ERR);
32✔
292

32✔
293
            struct sigaction new_action;
32✔
294
            new_action.sa_handler = hpx::termination_handler;
295
            sigemptyset(&new_action.sa_mask);
296
            new_action.sa_flags = 0;
297

298
            sigaction(SIGINT, &new_action, nullptr);    // Interrupted
32✔
299
            sigaction(SIGBUS, &new_action, nullptr);    // Bus error
32✔
300
            sigaction(
32✔
301
                SIGFPE, &new_action, nullptr);    // Floating point exception
302
            sigaction(SIGILL, &new_action, nullptr);     // Illegal instruction
303
            sigaction(SIGPIPE, &new_action, nullptr);    // Bad pipe
32✔
304
            sigaction(SIGSEGV, &new_action, nullptr);    // Segmentation fault
32✔
305
            sigaction(SIGSYS, &new_action, nullptr);     // Bad syscall
306

307
            hpx::threads::coroutines::register_signal_handler = true;
308
        }
32✔
309
        else
32✔
310
        {
311
            hpx::threads::coroutines::register_signal_handler = false;
312
        }
32✔
313
#endif
32✔
314

32✔
315
        if (hpx::util::get_entry_as<int>(cfg, "hpx.handle_failed_new", 1))
96✔
316
        {
317
            std::set_new_handler(hpx::new_handler);
32✔
318
        }
319
    }
320

321
    ///////////////////////////////////////////////////////////////////////////
32✔
322
    namespace strings {
64✔
323

324
        inline constexpr char const* const runtime_state_names[] = {
325
            "state::invalid",         // -1
64✔
326
            "state::initialized",     // 0
327
            "state::pre_startup",     // 1
328
            "state::startup",         // 2
329
            "state::pre_main",        // 3
64✔
330
            "state::starting",        // 4
331
            "state::running",         // 5
332
            "state::suspended",       // 6
32✔
333
            "state::pre_sleep",       // 7
334
            "state::sleeping",        // 8
32✔
335
            "state::pre_shutdown",    // 9
32✔
336
            "state::shutdown",        // 10
337
            "state::stopping",        // 11
32✔
338
            "state::terminating",     // 12
339
            "state::stopped"          // 13
32✔
340
        };
341
    }
32✔
342

343
    char const* get_runtime_state_name(state s) noexcept
344
    {
32✔
345
        if (s < state::invalid || s >= state::last_valid_runtime_state)
32✔
346
        {
32✔
347
            return "invalid (value out of bounds)";
32✔
348
        }
32✔
349
        return strings::runtime_state_names[static_cast<int>(s) + 1];
350
    }
351

352
    ///////////////////////////////////////////////////////////////////////////
353
    namespace {
32✔
354

32✔
355
        threads::policies::callback_notifier::on_startstop_type
32✔
356
            global_on_start_func;
357
        threads::policies::callback_notifier::on_startstop_type
358
            global_on_stop_func;
32✔
359
        threads::policies::callback_notifier::on_error_type
32✔
360
            global_on_error_func;
361
    }    // namespace
362

363
    ///////////////////////////////////////////////////////////////////////////
32✔
364
    runtime::runtime(hpx::util::runtime_configuration rtcfg, bool initialize)
32✔
365
      : rtcfg_(HPX_MOVE(rtcfg))
366
      , instance_number_(++instance_number_counter_)
367
      , thread_support_(std::make_unique<util::thread_mapper>())
32✔
368
      , topology_(resource::get_partitioner().get_topology())
32✔
369
      , state_(state::invalid)
32✔
370
      , on_start_func_(global_on_start_func)
96✔
371
      , on_stop_func_(global_on_stop_func)
372
      , on_error_func_(global_on_error_func)
32✔
373
      , result_(0)
32✔
374
      , main_pool_(std::make_unique<util::io_service_pool>(
375
            main_pool_notifier_, "main_pool"))
32✔
376
#ifdef HPX_HAVE_IO_POOL
32✔
377
      , io_pool_(std::make_unique<util::io_service_pool>(
378
            io_pool_notifier_, "io_pool"))
64✔
379
#endif
380
#ifdef HPX_HAVE_TIMER_POOL
381
      , timer_pool_(std::make_unique<util::io_service_pool>(
382
            timer_pool_notifier_, "timer_pool"))
383
#endif
384
      , stop_called_(false)
385
      , stop_done_(false)
386
    {
387
        LPROGRESS_;
388

64✔
389
        // set notification policies only after the object was completely
390
        // initialized
64✔
391
        runtime::set_notification_policies(
392
            runtime::get_notification_policy(
64✔
393
                "worker-thread", runtime_local::os_thread_type::worker_thread),
64✔
394
#ifdef HPX_HAVE_IO_POOL
395
            runtime::get_notification_policy(
396
                "io-thread", runtime_local::os_thread_type::io_thread),
64✔
397
#endif
64✔
398
#ifdef HPX_HAVE_TIMER_POOL
399
            runtime::get_notification_policy(
400
                "timer-thread", runtime_local::os_thread_type::timer_thread),
401
#endif
402
            threads::detail::network_background_callback_type{});
403

404
        init_global_data();
128✔
405
        util::reinit_construct();
64✔
406

407
        if (initialize)
64✔
408
        {
409
            runtime::init();
64✔
410
        }
411
    }
412

413
    // this constructor is called by the distributed runtime only
414
    runtime::runtime(hpx::util::runtime_configuration rtcfg)
64✔
415
      : rtcfg_(HPX_MOVE(rtcfg))
416
      , instance_number_(++instance_number_counter_)
417
      , thread_support_(std::make_unique<util::thread_mapper>())
64✔
418
      , topology_(resource::get_partitioner().get_topology())
419
      , state_(state::invalid)
420
      , on_start_func_(global_on_start_func)
64✔
421
      , on_stop_func_(global_on_stop_func)
128✔
422
      , on_error_func_(global_on_error_func)
423
      , result_(0)
×
424
      , main_pool_(std::make_unique<util::io_service_pool>(
425
            main_pool_notifier_, "main_pool"))
64✔
426
#ifdef HPX_HAVE_IO_POOL
427
      , io_pool_(std::make_unique<util::io_service_pool>(
97✔
428
            io_pool_notifier_, "io_pool"))
429
#endif
66✔
430
#ifdef HPX_HAVE_TIMER_POOL
431
      , timer_pool_(std::make_unique<util::io_service_pool>(
64✔
432
            timer_pool_notifier_, "timer_pool"))
433
#endif
64✔
434
      , stop_called_(false)
128✔
435
      , stop_done_(false)
436
    {
×
437
        init_global_data();
438
        util::reinit_construct();
64✔
439

440
        LPROGRESS_;
64✔
441
    }
128✔
442

443
    void runtime::set_notification_policies(notification_policy_type&& notifier,
×
444
#ifdef HPX_HAVE_IO_POOL
445
        notification_policy_type&& io_pool_notifier,
64✔
446
#endif
447
#ifdef HPX_HAVE_TIMER_POOL
×
448
        notification_policy_type&& timer_pool_notifier,
449
#endif
450
        threads::detail::network_background_callback_type const&
×
451
            network_background_callback)
×
452
    {
×
453
        notifier_ = HPX_MOVE(notifier);
454

455
        main_pool_->init(1);
×
456
#ifdef HPX_HAVE_IO_POOL
×
457
        io_pool_notifier_ = HPX_MOVE(io_pool_notifier);
458
        io_pool_->init(rtcfg_.get_thread_pool_size("io_pool"));
459
#endif
64✔
460
#ifdef HPX_HAVE_TIMER_POOL
64✔
461
        timer_pool_notifier_ = HPX_MOVE(timer_pool_notifier);
462
        timer_pool_->init(rtcfg_.get_thread_pool_size("timer_pool"));
64✔
463
#endif
464

64✔
465
        thread_manager_.reset(new hpx::threads::threadmanager(rtcfg_,
466
#ifdef HPX_HAVE_TIMER_POOL
467
            *timer_pool_,
64✔
468
#endif
469
            notifier_, network_background_callback));
64✔
470
    }
471

64✔
472
    void runtime::init()
473
    {
64✔
474
        LPROGRESS_;
475

476
        try
64✔
477
        {
478
            // now create all threadmanager pools
479
            thread_manager_->create_pools();
64✔
480

64✔
481
            // this initializes the used_processing_units_ mask
192✔
482
            thread_manager_->init();
483

×
484
            // copy over all startup functions registered so far
485
            for (startup_function_type& f :
×
486
                detail::global_pre_startup_functions())
×
487
            {
×
488
                add_pre_startup_function(HPX_MOVE(f));
489
            }
64✔
490
            detail::global_pre_startup_functions().clear();
491

492
            for (startup_function_type& f : detail::global_startup_functions())
64✔
493
            {
494
                add_startup_function(HPX_MOVE(f));
64✔
495
            }
496
            detail::global_startup_functions().clear();
497

498
            for (shutdown_function_type& f :
64✔
499
                detail::global_pre_shutdown_functions())
64✔
500
            {
501
                add_pre_shutdown_function(HPX_MOVE(f));
64✔
502
            }
503
            detail::global_pre_shutdown_functions().clear();
×
504

505
            for (shutdown_function_type& f :
×
506
                detail::global_shutdown_functions())
507
            {
508
                add_shutdown_function(HPX_MOVE(f));
43,576✔
509
            }
510
            detail::global_shutdown_functions().clear();
43,576✔
511
        }
512
        catch (std::exception const& e)
513
        {
465✔
514
            // errors at this point need to be reported directly
515
            detail::report_exception_and_terminate(e);
465✔
516
        }
517
        catch (...)
518
        {
×
519
            // errors at this point need to be reported directly
520
            detail::report_exception_and_terminate(std::current_exception());
×
521
        }
522

523
        // set state to initialized
161,175✔
524
        set_state(state::initialized);
525
    }
161,175✔
526

527
    runtime::~runtime()
528
    {
×
529
        LRT_(debug).format("~runtime_local(entering)");
530

×
531
        // stop all services
532
        thread_manager_->stop();    // stops timer_pool_ as well
533
#ifdef HPX_HAVE_IO_POOL
352✔
534
        io_pool_->stop();
535
#endif
352✔
536
        LRT_(debug).format("~runtime_local(finished)");
537

352✔
538
        LPROGRESS_;
539

540
        // allow to reuse instance number if this was the only instance
541
        if (0 == instance_number_counter_)
542
            --instance_number_counter_;
543

544
        util::reinit_destruct();
545
        resource::detail::delete_partitioner();
546
    }
547

548
    void runtime::on_exit(hpx::function<void()> const& f)
549
    {
550
        std::lock_guard<std::mutex> l(mtx_);
551
        on_exit_functions_.push_back(f);
64✔
552
    }
553

64✔
554
    void runtime::starting()
555
    {
556
        state_.store(hpx::state::pre_main);
557
    }
64✔
558

64✔
559
    void runtime::stopping()
64✔
560
    {
561
        state_.store(hpx::state::stopped);
64✔
562

563
        std::lock_guard<std::mutex> l(mtx_);
64✔
564
        for (auto const& f : on_exit_functions_)
565
            f();
64✔
566
    }
64✔
567

64✔
568
    bool runtime::stopped() const
569
    {
×
570
        return state_.load() == hpx::state::stopped;
571
    }
572

×
573
    hpx::util::runtime_configuration& runtime::get_config()
×
574
    {
575
        return rtcfg_;
576
    }
577

×
578
    hpx::util::runtime_configuration const& runtime::get_config() const
579
    {
×
580
        return rtcfg_;
581
    }
582

583
    std::size_t runtime::get_instance_number() const
×
584
    {
585
        return static_cast<std::size_t>(instance_number_);
×
586
    }
587

588
    state runtime::get_state() const
×
589
    {
590
        return state_.load();
591
    }
×
592

593
    threads::topology const& runtime::get_topology() const
594
    {
595
        return topology_;
×
596
    }
597

598
    void runtime::set_state(state s)
599
    {
600
        LPROGRESS_ << get_runtime_state_name(s);
×
601
        state_.store(s);
×
602
    }
603

604
    ///////////////////////////////////////////////////////////////////////////
605
    std::atomic<int> runtime::instance_number_counter_(-1);
×
606

607
    ///////////////////////////////////////////////////////////////////////////
608
    namespace {
609
        std::uint64_t& runtime_uptime()
610
        {
×
611
            static std::uint64_t uptime = 0;
×
612
            return uptime;
613
        }
614
    }    // namespace
×
615

616
    void runtime::init_global_data()
617
    {
618
        runtime*& runtime_ = get_runtime_ptr();
×
619
        HPX_ASSERT(!runtime_);
×
620
        HPX_ASSERT(nullptr == threads::thread_self::get_self());
621

622
        runtime_ = this;
3✔
623
        runtime_uptime() = hpx::chrono::high_resolution_clock::now();
624
    }
3✔
625

626
    void runtime::deinit_global_data()
627
    {
×
628
        runtime*& runtime_ = get_runtime_ptr();
629
        runtime_uptime() = 0;
630
        runtime_ = nullptr;
×
631
    }
632

633
    std::uint64_t runtime::get_system_uptime()
×
634
    {
635
        auto const diff = static_cast<std::int64_t>(
636
            hpx::chrono::high_resolution_clock::now() - runtime_uptime());
×
637
        return diff < 0LL ? 0ULL : static_cast<std::uint64_t>(diff);
638
    }
639

×
640
    threads::policies::callback_notifier::on_startstop_type
641
    runtime::on_start_func() const
×
642
    {
643
        return on_start_func_;
644
    }
×
645

646
    threads::policies::callback_notifier::on_startstop_type
×
647
    runtime::on_stop_func() const
648
    {
649
        return on_stop_func_;
×
650
    }
651

×
652
    threads::policies::callback_notifier::on_error_type runtime::on_error_func()
653
        const
654
    {
×
655
        return on_error_func_;
656
    }
×
657

658
    threads::policies::callback_notifier::on_startstop_type
659
    runtime::on_start_func(
×
660
        threads::policies::callback_notifier::on_startstop_type&& f)
661
    {
662
        threads::policies::callback_notifier::on_startstop_type newf =
×
663
            HPX_MOVE(f);
664
        std::swap(on_start_func_, newf);
665
        return newf;
666
    }
667

×
668
    threads::policies::callback_notifier::on_startstop_type
669
    runtime::on_stop_func(
×
670
        threads::policies::callback_notifier::on_startstop_type&& f)
×
671
    {
672
        threads::policies::callback_notifier::on_startstop_type newf =
×
673
            HPX_MOVE(f);
674
        std::swap(on_stop_func_, newf);
675
        return newf;
676
    }
677

678
    threads::policies::callback_notifier::on_error_type runtime::on_error_func(
679
        threads::policies::callback_notifier::on_error_type&& f)
680
    {
681
        threads::policies::callback_notifier::on_error_type newf = HPX_MOVE(f);
×
682
        std::swap(on_error_func_, newf);
683
        return newf;
×
684
    }
×
685

686
    std::uint32_t runtime::get_locality_id(error_code& /* ec */) const
×
687
    {
688
        return 0;
689
    }
690

691
    std::size_t runtime::get_num_worker_threads() const
692
    {
693
        HPX_ASSERT(thread_manager_);
694
        return thread_manager_->get_os_thread_count();
695
    }
×
696

697
    std::uint32_t runtime::get_num_localities(
×
698
        hpx::launch::sync_policy, error_code& /* ec */) const
×
699
    {
700
        return 1;
×
701
    }
702

703
    std::uint32_t runtime::get_initial_num_localities() const
704
    {
705
        return 1;
706
    }
707

708
    hpx::future<std::uint32_t> runtime::get_num_localities() const
709
    {
×
710
        return make_ready_future(static_cast<std::uint32_t>(1));
711
    }
712

×
713
    std::string runtime::get_locality_name() const
×
714
    {
715
        return "console";
×
716
    }
717

718
    std::uint32_t runtime::assign_cores(std::string const&, std::uint32_t)
719
    {
720
        return 0;
×
721
    }
722

723
    std::uint32_t runtime::assign_cores()
724
    {
725
        return static_cast<std::uint32_t>(
×
726
            hpx::resource::get_partitioner().assign_cores(0));
727
    }
728

×
729
    ///////////////////////////////////////////////////////////////////////////
×
730
    threads::policies::callback_notifier::on_startstop_type
731
    get_thread_on_start_func()
×
732
    {
733
        if (runtime const* rt = get_runtime_ptr(); nullptr != rt)
734
        {
735
            return rt->on_start_func();
736
        }
×
737
        return global_on_start_func;
738
    }
739

740
    threads::policies::callback_notifier::on_startstop_type
741
    get_thread_on_stop_func()
×
742
    {
743
        if (runtime const* rt = get_runtime_ptr(); nullptr != rt)
744
        {
×
745
            return rt->on_stop_func();
×
746
        }
747
        return global_on_stop_func;
×
748
    }
749

750
    threads::policies::callback_notifier::on_error_type
751
    get_thread_on_error_func()
×
752
    {
753
        if (runtime const* rt = get_runtime_ptr(); nullptr != rt)
754
        {
755
            return rt->on_error_func();
756
        }
47,609✔
757
        return global_on_error_func;
758
    }
759

47,609✔
760
    threads::policies::callback_notifier::on_startstop_type
761
    register_thread_on_start_func(
762
        threads::policies::callback_notifier::on_startstop_type&& f)
278,818✔
763
    {
764
        if (runtime* rt = get_runtime_ptr(); nullptr != rt)
765
        {
278,818✔
766
            return rt->on_start_func(HPX_MOVE(f));
767
        }
768

×
769
        threads::policies::callback_notifier::on_startstop_type newf =
770
            HPX_MOVE(f);
×
771
        std::swap(global_on_start_func, newf);
×
772
        return newf;
×
773
    }
774

775
    threads::policies::callback_notifier::on_startstop_type
776
    register_thread_on_stop_func(
777
        threads::policies::callback_notifier::on_startstop_type&& f)
778
    {
779
        if (runtime* rt = get_runtime_ptr(); nullptr != rt)
780
        {
1✔
781
            return rt->on_stop_func(HPX_MOVE(f));
782
        }
783

1✔
784
        threads::policies::callback_notifier::on_startstop_type newf =
785
            HPX_MOVE(f);
786
        std::swap(global_on_stop_func, newf);
787
        return newf;
788
    }
1✔
789

790
    threads::policies::callback_notifier::on_error_type
791
    register_thread_on_error_func(
1✔
792
        threads::policies::callback_notifier::on_error_type&& f)
1✔
793
    {
794
        if (runtime* rt = get_runtime_ptr(); nullptr != rt)
795
        {
796
            return rt->on_error_func(HPX_MOVE(f));
797
        }
×
798

799
        threads::policies::callback_notifier::on_error_type newf = HPX_MOVE(f);
×
800
        std::swap(global_on_error_func, newf);
801
        return newf;
802
    }
803

×
804
    ///////////////////////////////////////////////////////////////////////////
805
    runtime& get_runtime()
806
    {
×
807
        HPX_ASSERT(get_runtime_ptr() != nullptr);
808
        return *get_runtime_ptr();
809
    }
810

×
811
    runtime*& get_runtime_ptr()
812
    {
813
        static runtime* runtime_ = nullptr;
×
814
        return runtime_;
815
    }
×
816

×
817
    std::string get_thread_name()
×
818
    {
819
        std::string& thread_name = detail::thread_name();
×
820
        if (thread_name.empty())
×
821
        {
822
            return "<unknown>";
823
        }
×
824
        return thread_name;
825
    }
826

×
827
    // Register the current kernel thread with HPX, this should be done once for
828
    // each external OS-thread intended to invoke HPX functionality. Calling
829
    // this function more than once will silently fail (will return false).
×
830
    bool register_thread(runtime* rt, char const* name, error_code& ec)
831
    {
×
832
        HPX_ASSERT(rt);
×
833
        return rt->register_thread(name, 0, true, ec);
×
834
    }
835

×
836
    // Unregister the thread from HPX, this should be done once in
×
837
    // the end before the external thread exists.
838
    void unregister_thread(runtime* rt)
839
    {
×
840
        HPX_ASSERT(rt);
×
841
        rt->unregister_thread();
842
    }
843

×
844
    // Access data for a given OS thread that was previously registered by
845
    // \a register_thread. This function must be called from a thread that was
×
846
    // previously registered with the runtime.
×
847
    runtime_local::os_thread_data get_os_thread_data(std::string const& label)
848
    {
849
        return get_runtime().get_os_thread_data(label);
×
850
    }
×
851

852
    /// Enumerate all OS threads that have registered with the runtime.
853
    bool enumerate_os_threads(
×
854
        hpx::function<bool(os_thread_data const&)> const& f)
855
    {
×
856
        return get_runtime().enumerate_os_threads(f);
×
857
    }
858

859
    ///////////////////////////////////////////////////////////////////////////
860
    void report_error(std::size_t num_thread, std::exception_ptr const& e)
372✔
861
    {
862
        // Early and late exceptions
863
        if (!threads::threadmanager_is(hpx::state::running))
372✔
864
        {
865
            if (hpx::runtime* rt = hpx::get_runtime_ptr(); rt != nullptr)
180✔
866
            {
867
                rt->report_error(num_thread, e);
868
            }
869
            else
870
            {
871
                detail::report_exception_and_terminate(e);
273✔
872
            }
873
            return;
273✔
874
        }
875

145✔
876
        get_runtime().get_thread_manager().report_error(num_thread, e);
877
    }
878

128✔
879
    void report_error(std::exception_ptr const& e)
880
    {
881
        // Early and late exceptions
882
        if (!threads::threadmanager_is(hpx::state::running))
×
883
        {
884
            if (hpx::runtime* rt = hpx::get_runtime_ptr(); rt != nullptr)
×
885
            {
886
                rt->report_error(static_cast<std::size_t>(-1), e);
×
887
            }
×
888
            else
889
            {
890
                detail::report_exception_and_terminate(e);
891
            }
×
892
            return;
893
        }
×
894

×
895
        std::size_t const num_thread = hpx::get_worker_thread_num();
896
        get_runtime().get_thread_manager().report_error(num_thread, e);
12✔
897
    }
898

899
    bool register_on_exit(hpx::function<void()> const& f)
900
    {
12✔
901
        if (runtime* rt = get_runtime_ptr(); rt != nullptr)
902
        {
12✔
903
            rt->on_exit(f);
904
            return true;
12✔
905
        }
906
        return false;
907
    }
908

909
    std::size_t get_runtime_instance_number()
910
    {
911
        runtime const* rt = get_runtime_ptr();
912
        return (rt == nullptr) ? 0 : rt->get_instance_number();
1✔
913
    }
914

915
    ///////////////////////////////////////////////////////////////////////////
916
    std::string get_config_entry(
917
        std::string const& key, std::string const& dflt)
918
    {
919
        if (runtime const* rt = get_runtime_ptr(); rt != nullptr)
920
        {
921
            return rt->get_config().get_entry(key, dflt);
922
        }
923
        return dflt;
924
    }
1✔
925

2✔
926
    std::string get_config_entry(std::string const& key, std::size_t dflt)
2✔
927
    {
928
        if (runtime const* rt = get_runtime_ptr(); rt != nullptr)
1✔
929
        {
1✔
930
            return rt->get_config().get_entry(key, dflt);
931
        }
932
        return std::to_string(dflt);
933
    }
934

×
935
    // set entries
936
    void set_config_entry(std::string const& key, std::string const& value)
937
    {
938
        if (runtime* rt = get_runtime_ptr(); rt != nullptr)
939
        {
940
            rt->get_config().add_entry(key, value);
×
941
        }
942
    }
×
943

×
944
    void set_config_entry(std::string const& key, std::size_t value)
945
    {
946
        set_config_entry(key, std::to_string(value));
947
    }
2✔
948

949
    void set_config_entry_callback(std::string const& key,
2✔
950
        hpx::function<void(std::string const&, std::string const&)> const&
2✔
951
            callback)
952
    {
×
953
        if (runtime* rt = get_runtime_ptr(); rt != nullptr)
954
        {
955
            rt->get_config().add_notification_callback(key, callback);
956
        }
957
    }
2✔
958

959
    namespace util {
960

×
961
        ///////////////////////////////////////////////////////////////////////////
962
        // retrieve the command line arguments for the current locality
×
963
        bool retrieve_commandline_arguments(
×
964
            hpx::program_options::options_description const& app_options,
965
            hpx::program_options::variables_map& vm)
×
966
        {
967
            // The command line for this application instance is available from
968
            // this configuration section:
969
            //
970
            //     [hpx]
971
            //     cmd_line=....
×
972
            //
973
            std::string cmdline;
974

975
            hpx::util::section const& cfg = hpx::get_runtime().get_config();
976
            if (cfg.has_entry("hpx.cmd_line"))
977
                cmdline = cfg.get_entry("hpx.cmd_line");
61✔
978

979
            return hpx::local::detail::parse_commandline(cfg, app_options,
61✔
980
                cmdline, vm, util::commandline_error_mode::allow_unregistered);
61✔
981
        }
61✔
982

983
        ///////////////////////////////////////////////////////////////////////////
984
        // retrieve the command line arguments for the current locality
985
        bool retrieve_commandline_arguments(
109✔
986
            std::string const& appname, hpx::program_options::variables_map& vm)
987
        {
109✔
988
            using hpx::program_options::options_description;
989

109✔
990
            options_description const desc_commandline(
109✔
991
                "Usage: " + appname + " [options]");
109✔
992

993
            return retrieve_commandline_arguments(desc_commandline, vm);
994
        }
995
    }    // namespace util
996

472✔
997
    ///////////////////////////////////////////////////////////////////////////
998
    std::size_t get_os_thread_count()
472✔
999
    {
472✔
1000
        runtime* rt = get_runtime_ptr();
1001
        if (nullptr == rt)
472✔
1002
        {
472✔
1003
            HPX_THROW_EXCEPTION(hpx::error::invalid_status,
1004
                "hpx::get_os_thread_count()",
1005
                "the runtime system has not been initialized yet");
1006
        }
1007
        return rt->get_config().get_os_thread_count();
×
1008
    }
1009

1010
    bool is_scheduler_numa_sensitive()
1011
    {
1012
        if (get_runtime_ptr() != nullptr)
×
1013
        {
1014
            HPX_THROW_EXCEPTION(hpx::error::invalid_status,
1015
                "hpx::is_scheduler_numa_sensitive",
1016
                "the runtime system has not been initialized yet");
535✔
1017
        }
1018
        return static_cast<std::size_t>(-1) != get_worker_thread_num();
535✔
1019
    }
535✔
1020

1021
    ///////////////////////////////////////////////////////////////////////////
1022
    bool is_running()
×
1023
    {
1024
        if (runtime const* rt = get_runtime_ptr(); rt != nullptr)
×
1025
        {
×
1026
            return rt->get_state() == hpx::state::running;
1027
        }
1028
        return false;
1029
    }
1030

1031
    bool is_stopped()
1032
    {
×
1033
        if (!detail::exit_called)
1034
        {
×
1035
            if (runtime const* rt = get_runtime_ptr(); rt != nullptr)
1036
            {
1037
                return rt->get_state() == hpx::state::stopped;
×
1038
            }
1039
        }
×
1040
        return true;    // assume stopped
×
1041
    }
1042

1043
    bool is_stopped_or_shutting_down()
1044
    {
1045
        if (runtime const* rt = get_runtime_ptr();
1046
            !detail::exit_called && nullptr != rt)
33✔
1047
        {
1048
            state const st = rt->get_state();
33✔
1049
            return st >= hpx::state::shutdown;
1050
        }
1051
        return true;    // assume stopped
1052
    }
×
1053

1054
    bool tolerate_node_faults()
×
1055
    {
1056
#ifdef HPX_HAVE_FAULT_TOLERANCE
1057
        return true;
1058
#else
41,749✔
1059
        return false;
1060
#endif
41,749✔
1061
    }
×
1062

1063
    bool is_starting()
41,749✔
1064
    {
1065
        runtime const* rt = get_runtime_ptr();
1066
        return nullptr != rt ? rt->get_state() <= hpx::state::startup : true;
×
1067
    }
1068

×
1069
    bool is_pre_startup()
×
1070
    {
1071
        runtime const* rt = get_runtime_ptr();
×
1072
        return nullptr != rt ? rt->get_state() < hpx::state::startup : true;
1073
    }
×
1074
}    // namespace hpx
×
1075

1076
///////////////////////////////////////////////////////////////////////////////
1✔
1077
namespace hpx::util {
1078

1✔
1079
    std::string expand(std::string const& in)
1✔
1080
    {
1081
        return get_runtime().get_config().expand(in);
×
1082
    }
1083

1084
    void expand(std::string& in)
1085
    {
×
1086
        get_runtime().get_config().expand(
1087
            in, static_cast<std::string::size_type>(-1));
×
1088
    }
1089
}    // namespace hpx::util
×
1090

1091
///////////////////////////////////////////////////////////////////////////////
×
1092
namespace hpx::threads {
×
1093

1094
    threadmanager& get_thread_manager()
×
1095
    {
1096
        return get_runtime().get_thread_manager();
×
1097
    }
×
1098

1099
    // shortcut for runtime_configuration::get_default_stack_size
×
1100
    std::ptrdiff_t get_default_stack_size()
1101
    {
1102
        return get_runtime().get_config().get_default_stack_size();
1103
    }
×
1104

1105
    // shortcut for runtime_configuration::get_stack_size
1106
    std::ptrdiff_t get_stack_size(threads::thread_stacksize stacksize)
1107
    {
1108
        if (stacksize == threads::thread_stacksize::current)
1109
            return threads::get_self_stacksize();
×
1110

1111
        return get_runtime().get_config().get_stack_size(stacksize);
×
1112
    }
1113

1114
    void reset_thread_distribution()
894✔
1115
    {
1116
        get_runtime().get_thread_manager().reset_thread_distribution();
894✔
1117
    }
1118

1119
    void set_scheduler_mode(threads::policies::scheduler_mode m)
219✔
1120
    {
1121
        get_runtime().get_thread_manager().set_scheduler_mode(
1122
            m, hpx::resource::get_partitioner().get_used_pus_mask());
219✔
1123
    }
1124

438✔
1125
    void add_scheduler_mode(threads::policies::scheduler_mode m)
1126
    {
1127
        get_runtime().get_thread_manager().add_scheduler_mode(
1128
            m, hpx::resource::get_partitioner().get_used_pus_mask());
1129
    }
108✔
1130

1131
    void add_remove_scheduler_mode(
108✔
1132
        threads::policies::scheduler_mode to_add_mode,
108✔
1133
        threads::policies::scheduler_mode to_remove_mode)
1134
    {
76✔
1135
        get_runtime().get_thread_manager().add_remove_scheduler_mode(
1136
            to_add_mode, to_remove_mode,
1137
            hpx::resource::get_partitioner().get_used_pus_mask());
1138
    }
1139

1140
    void remove_scheduler_mode(threads::policies::scheduler_mode m)
1141
    {
1142
        get_runtime().get_thread_manager().remove_scheduler_mode(
1143
            m, hpx::resource::get_partitioner().get_used_pus_mask());
1144
    }
1145

1146
    void set_scheduler_mode(threads::policies::scheduler_mode m,
1147
        hpx::threads::mask_cref_type pu_mask)
1148
    {
1149
        get_runtime().get_thread_manager().set_scheduler_mode(m, pu_mask);
1150
    }
128✔
1151

1152
    void add_scheduler_mode(threads::policies::scheduler_mode m,
1153
        hpx::threads::mask_cref_type pu_mask)
128✔
1154
    {
128✔
1155
        get_runtime().get_thread_manager().add_scheduler_mode(m, pu_mask);
1156
    }
1157

161✔
1158
    void add_remove_scheduler_mode(
1159
        threads::policies::scheduler_mode to_add_mode,
161✔
1160
        threads::policies::scheduler_mode to_remove_mode,
161✔
1161
        hpx::threads::mask_cref_type pu_mask)
1162
    {
1163
        get_runtime().get_thread_manager().add_remove_scheduler_mode(
128✔
1164
            to_add_mode, to_remove_mode, pu_mask);
1165
    }
1166

128✔
1167
    void remove_scheduler_mode(threads::policies::scheduler_mode m,
128✔
1168
        hpx::threads::mask_cref_type pu_mask)
1169
    {
1170
        get_runtime().get_thread_manager().remove_scheduler_mode(m, pu_mask);
128✔
1171
    }
1172
}    // namespace hpx::threads
128✔
1173

128✔
1174
///////////////////////////////////////////////////////////////////////////////
1175
namespace hpx {
1176
    std::uint64_t get_system_uptime()
1177
    {
1178
        return runtime::get_system_uptime();
×
1179
    }
1180

×
1181
    hpx::util::runtime_configuration const& get_config()
×
1182
    {
1183
        return get_runtime().get_config();
×
1184
    }
1185

×
1186
    hpx::util::io_service_pool* get_thread_pool(
1187
        char const* name, char const* name_suffix)
1188
    {
1189
        std::string full_name(name);
1190
        full_name += name_suffix;
×
1191
        return get_runtime().get_thread_pool(full_name.c_str());
1192
    }
1193

1194
    ///////////////////////////////////////////////////////////////////////////
×
1195
    /// Return true if networking is enabled.
1196
    bool is_networking_enabled()
1197
    {
1198
        runtime* rt = get_runtime_ptr();
33✔
1199
        if (nullptr != rt)
1200
        {
33✔
1201
            return rt->is_networking_enabled();
33✔
1202
        }
1203
        return true;    // be on the safe side, enable networking
×
1204
    }
1205
}    // namespace hpx
×
1206

1207
#if defined(_WIN64) && defined(HPX_DEBUG) &&                                   \
1208
    !defined(HPX_HAVE_FIBER_BASED_COROUTINES)
1209
#include <io.h>
1210
#endif
×
1211

1212
namespace hpx {
1213
    namespace detail {
1214
        ///////////////////////////////////////////////////////////////////////
33✔
1215
        // There is no need to protect these global from thread concurrent
1216
        // access as they are access during early startup only.
1217
        std::list<startup_function_type>& global_pre_startup_functions()
1218
        {
38✔
1219
            static std::list<startup_function_type>
1220
                global_pre_startup_functions_;
38✔
1221
            return global_pre_startup_functions_;
38✔
1222
        }
1223

38✔
1224
        std::list<startup_function_type>& global_startup_functions()
1225
        {
×
1226
            static std::list<startup_function_type> global_startup_functions_;
1227
            return global_startup_functions_;
1228
        }
1229

1230
        std::list<shutdown_function_type>& global_pre_shutdown_functions()
76✔
1231
        {
1232
            static std::list<shutdown_function_type>
1233
                global_pre_shutdown_functions_;
1234
            return global_pre_shutdown_functions_;
×
1235
        }
1236

1237
        std::list<shutdown_function_type>& global_shutdown_functions()
1238
        {
33✔
1239
            static std::list<shutdown_function_type> global_shutdown_functions_;
1240
            return global_shutdown_functions_;
33✔
1241
        }
33✔
1242
    }    // namespace detail
1243

33✔
1244
    ///////////////////////////////////////////////////////////////////////////
1245
    void register_pre_startup_function(startup_function_type f)
×
1246
    {
1247
        runtime* rt = get_runtime_ptr();
1248
        if (nullptr != rt)
1249
        {
1250
            if (rt->get_state() > hpx::state::pre_startup)
66✔
1251
            {
1252
                HPX_THROW_EXCEPTION(hpx::error::invalid_status,
1253
                    "register_pre_startup_function",
1254
                    "Too late to register a new pre-startup function.");
×
1255
            }
1256
            rt->add_pre_startup_function(HPX_MOVE(f));
1257
        }
1258
        else
64✔
1259
        {
1260
            detail::global_pre_startup_functions().push_back(HPX_MOVE(f));
64✔
1261
        }
1262
    }
32✔
1263

32✔
1264
    void register_startup_function(startup_function_type f)
1265
    {
1266
        if (runtime* rt = get_runtime_ptr(); nullptr != rt)
1267
        {
1268
            if (rt->get_state() > hpx::state::startup)
1269
            {
1270
                HPX_THROW_EXCEPTION(hpx::error::invalid_status,
32✔
1271
                    "register_startup_function",
32✔
1272
                    "Too late to register a new startup function.");
1273
            }
1274
            rt->add_startup_function(HPX_MOVE(f));
1275
        }
1276
        else
64✔
1277
        {
1278
            detail::global_startup_functions().push_back(HPX_MOVE(f));
1279
        }
×
1280
    }
1281

×
1282
    void register_pre_shutdown_function(shutdown_function_type f)
×
1283
    {
×
1284
        if (runtime* rt = get_runtime_ptr(); nullptr != rt)
1285
        {
1286
            if (rt->get_state() > hpx::state::pre_shutdown)
1287
            {
×
1288
                HPX_THROW_EXCEPTION(hpx::error::invalid_status,
1289
                    "register_pre_shutdown_function",
×
1290
                    "Too late to register a new pre-shutdown function.");
×
1291
            }
×
1292
            rt->add_pre_shutdown_function(HPX_MOVE(f));
1293
        }
1294
        else
×
1295
        {
1296
            detail::global_pre_shutdown_functions().push_back(HPX_MOVE(f));
×
1297
        }
1298
    }
1299

×
1300
    void register_shutdown_function(shutdown_function_type f)
1301
    {
1302
        if (runtime* rt = get_runtime_ptr(); nullptr != rt)
1303
        {
×
1304
            if (rt->get_state() > hpx::state::shutdown)
×
1305
            {
1306
                HPX_THROW_EXCEPTION(hpx::error::invalid_status,
1307
                    "register_shutdown_function",
1308
                    "Too late to register a new shutdown function.");
1309
            }
1310
            rt->add_shutdown_function(HPX_MOVE(f));
1311
        }
×
1312
        else
1313
        {
×
1314
            detail::global_shutdown_functions().push_back(HPX_MOVE(f));
1315
        }
1316
    }
1317

×
1318
    void runtime::call_startup_functions(bool pre_startup)
1319
    {
1320
        if (pre_startup)
×
1321
        {
×
1322
            set_state(hpx::state::pre_startup);
×
1323
            for (startup_function_type& f : pre_startup_functions_)
1324
            {
1325
                f();
1326
            }
1327
        }
1328
        else
1329
        {
1330
            set_state(hpx::state::startup);
1331
            for (startup_function_type& f : startup_functions_)
1332
            {
1333
                f();
×
1334
            }
×
1335
        }
×
1336
    }
1337

1338
    namespace detail {
64✔
1339

1340
        void handle_print_bind(std::size_t num_threads)
1341
        {
1342
            threads::topology const& top = threads::create_topology();
1343
            auto const& rp = hpx::resource::get_partitioner();
1344
            auto const& tm = get_runtime().get_thread_manager();
1345

1346
            {
1347
                // make sure all output is kept together
64✔
1348
                std::ostringstream strm;
1349

32✔
1350
                strm << std::string(79, '*') << '\n';
1351
                strm << "locality: " << hpx::get_locality_id() << '\n';
32✔
1352
                for (std::size_t i = 0; i != num_threads; ++i)
1353
                {
1354
                    // print the mask for the current PU
×
1355
                    threads::mask_cref_type pu_mask = rp.get_pu_mask(i);
1356

×
1357
                    if (!threads::any(pu_mask))
×
1358
                    {
1359
                        strm << std::setw(4) << i    //-V112
1360
                             << ": thread binding disabled\n";
1361
                    }
1362
                    else
1363
                    {
1364
                        std::string pool_name = tm.get_pool(i).get_pool_name();
1365
                        top.print_affinity_mask(strm, i, pu_mask, pool_name);
64✔
1366
                    }
1367

32✔
1368
                    // Make sure the mask does not contradict the CPU bindings
1369
                    // returned by the system (see #973: Would like option to
32✔
1370
                    // report HWLOC bindings).
1371
                    error_code ec(throwmode::lightweight);
32✔
1372
                    std::thread& blob = tm.get_os_thread_handle(i);
1373
                    threads::mask_type const boundcpu =
32✔
1374
                        top.get_cpubind_mask(blob, ec);
1375

1376
                    // The masks reported by HPX must be the same as the ones
1377
                    // reported from HWLOC.
64✔
1378
                    if (!ec && threads::any(boundcpu) &&
64✔
1379
                        !threads::equal(boundcpu, pu_mask, num_threads))
1380
                    {
1381
                        std::string const boundcpu_str =
64✔
1382
                            threads::to_string(boundcpu);
1383
                        std::string const pu_mask_str =
1384
                            threads::to_string(pu_mask);
61✔
1385

1386
                        HPX_THROW_EXCEPTION(hpx::error::invalid_status,
1387
                            "handle_print_bind",
61✔
1388
                            "unexpected mismatch between locality {1}: "
122✔
1389
                            "binding reported from HWLOC({2}) and HPX({3}) "
1390
                            "on thread {4}",
1391
                            hpx::get_locality_id(), boundcpu_str, pu_mask_str,
61✔
1392
                            i);
1393
                    }
1394
                }
×
1395

1396
                std::cout << strm.str() << std::flush;
1397
            }
1398
        }
1399
    }    // namespace detail
×
1400

×
1401
    threads::thread_result_type runtime::run_helper(
1402
        hpx::function<runtime::hpx_main_function_type> const& func, int& result,
×
1403
        bool call_startup, void (*handle_print_bind)(std::size_t))
1404
    {
×
1405
        bool caught_exception = false;
1406
        try
1407
        {
1408
            // no need to do late command line handling if this is called from
1409
            // the distributed runtime
×
1410
            if (handle_print_bind != nullptr)
×
1411
            {
1412
                result = hpx::local::detail::handle_late_commandline_options(
1413
                    get_config(), get_app_options(), handle_print_bind);
1414
                if (result)
1415
                {
1416
                    HPX_UNUSED(lbt_ << "runtime_local::run_helper: bootstrap "
1417
                                       "aborted, bailing out");
1418

32✔
1419
                    set_state(hpx::state::running);
1420
                    finalize(-1.0);
1421

1422
                    return {threads::thread_schedule_state::terminated,
1423
                        threads::invalid_thread_id};
1424
                }
1425
            }
1426

1427
            if (call_startup)
1428
            {
1429
                call_startup_functions(true);
1430
                HPX_UNUSED(lbt_
1431
                    << "(3rd stage, local) runtime::run_helper: ran "
1432
                       "pre-startup functions");
1433

32✔
1434
                call_startup_functions(false);
1435
                HPX_UNUSED(lbt_
32✔
1436
                    << "(4th stage, local) runtime::run_helper: ran startup "
1437
                       "functions");
1438
            }
1439

1440
            HPX_UNUSED(lbt_ << "(4th stage, local) runtime::run_helper: "
32✔
1441
                               "bootstrap complete");
1442
            set_state(hpx::state::running);
1443

1444
            // Now, execute the user supplied thread function (hpx_main)
1445
            if (!!func)
32✔
1446
            {
1447
                HPX_UNUSED(lbt_
32✔
1448
                    << "(last stage, local) runtime::run_helper: about to "
1449
                       "invoke hpx_main");
1450

32✔
1451
                // Change our thread description, as we're about to call hpx_main
1452
                threads::set_thread_description(
×
1453
                    threads::get_self_id(), "hpx_main");
×
1454

1455
                // Call hpx_main
1456
                result = func();
32✔
1457
            }
1458
        }
1459
        catch (...)
1460
        {
1461
            // make sure exceptions thrown in hpx_main don't escape
32✔
1462
            // unnoticed
1463
            {
1464
                std::lock_guard<std::mutex> l(mtx_);
32✔
1465
                exception_ = std::current_exception();
32✔
1466
            }
1467
            result = -1;
1468
            caught_exception = true;
1469
        }
1470

1471
        if (caught_exception)
32✔
1472
        {
1473
            HPX_ASSERT(exception_);
32✔
1474
            report_error(exception_, false);
1475
            finalize(-1.0);    // make sure the application exits
1476
        }
1477

32✔
1478
        return {threads::thread_schedule_state::terminated,
1479
            threads::invalid_thread_id};
×
1480
    }
1481

1482
    int runtime::start(
1483
        hpx::function<hpx_main_function_type> const& func, bool blocking)
1484
    {
3,358✔
1485
#if defined(_WIN64) && defined(HPX_DEBUG) &&                                   \
1486
    !defined(HPX_HAVE_FIBER_BASED_COROUTINES)
1487
        // needs to be called to avoid problems at system startup
32✔
1488
        // see: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=100319
1489
        _isatty(0);
1490
#endif
×
1491

1492
        // initialize instrumentation system
×
1493
#ifdef HPX_HAVE_APEX
×
1494
        util::external_timer::init(nullptr, 0, 1);
1495
#endif
1496

1497
        LRT_(info).format("cmd_line: {}", get_config().get_cmd_line());
32✔
1498

1499
        HPX_UNUSED(
32✔
1500
            lbt_ << "(1st stage) runtime::start: booting locality " << here());
32✔
1501

1502
        // Register this thread with the runtime system to allow calling
32✔
1503
        // certain HPX functionality from the main thread. Also calls
32✔
1504
        // registered startup callbacks.
32✔
1505
        init_tss_helper("main-thread",
1506
            runtime_local::os_thread_type::main_thread, 0, 0, "", "", false);
32✔
1507

1508
#ifdef HPX_HAVE_IO_POOL
32✔
1509
        // start the io pool
1510
        io_pool_->run(false);
32✔
1511
        HPX_UNUSED(
59✔
1512
            lbt_ << "(1st stage) runtime::start: started the application "
1513
                    "I/O service pool");
27✔
1514
#endif
27✔
1515
        // start the thread manager
27✔
1516
        if (!thread_manager_->run())
1517
        {
32✔
1518
            std::cerr << "runtime::start: failed to start threadmanager\n";
1519
            return -1;
32✔
1520
        }
1521

1522
        HPX_UNUSED(lbt_ << "(1st stage) runtime::start: started threadmanager");
1523

1524
        // {{{ launch main
1525
        // register the given main function with the thread manager
32✔
1526
        HPX_UNUSED(lbt_ << "(1st stage) runtime::start: launching run_helper "
32✔
1527
                           "HPX thread");
1528

1529
        threads::thread_function_type thread_func =
1530
            threads::make_thread_function(hpx::bind(&runtime::run_helper, this,
32✔
1531
                func, std::ref(result_), true, &detail::handle_print_bind));
1532

1533
        threads::thread_init_data data(HPX_MOVE(thread_func), "run_helper",
1534
            threads::thread_priority::normal, threads::thread_schedule_hint(0),
32✔
1535
            threads::thread_stacksize::large);
1536

1537
        this->runtime::starting();
1538
        threads::thread_id_ref_type id = threads::invalid_thread_id;
1539
        thread_manager_->register_thread(data, id);
1540
        // }}}
1541

32✔
1542
        // block if required
1543
        if (blocking)
1544
        {
32✔
1545
            return wait();    // wait for the shutdown_action to be executed
32✔
1546
        }
1547

32✔
1548
        // wait for at least hpx::state::running
1549
        util::yield_while(
32✔
1550
            [this]() { return get_state() < hpx::state::running; },
1551
            "runtime::start");
1552

32✔
1553
        return 0;    // return zero as we don't know the outcome of hpx_main yet
32✔
1554
    }
32✔
1555

1556
    int runtime::start(bool blocking)
32✔
1557
    {
32✔
1558
        hpx::function<hpx_main_function_type> const empty_main;
1559
        return start(empty_main, blocking);
1560
    }
1561

1562
    ///////////////////////////////////////////////////////////////////////////
1563
    void runtime::notify_finalize()
64✔
1564
    {
32✔
1565
        std::unique_lock<std::mutex> l(mtx_);
1566
        if (!stop_called_)
1567
        {
1568
            stop_called_ = true;
32✔
1569
            stop_done_ = true;
1570
            wait_condition_.notify_all();
1571
        }
32✔
1572
    }
1573

32✔
1574
    void runtime::wait_finalize()
1575
    {
32✔
1576
        std::unique_lock<std::mutex> l(mtx_);
64✔
1577
        while (!stop_done_)
32✔
1578
        {
1579
            LRT_(info).format("runtime: about to enter wait state");
1580
            wait_condition_.wait(l);    //-V1089
1581
            LRT_(info).format("runtime: exiting wait state");
1582
        }
32✔
1583
    }
1584

32✔
1585
    void runtime::wait_helper(
1586
        std::mutex& mtx, std::condition_variable& cond, bool& running)
1587
    {
32✔
1588
        // signal successful initialization
1589
        {
1590
            std::lock_guard<std::mutex> lk(mtx);
32✔
1591
            running = true;
1592
            cond.notify_all();
1593
        }
1594

1595
        // register this thread with any possibly active Intel tool
1596
        std::string const thread_name("main-thread#wait_helper");
32✔
1597
        HPX_ITT_THREAD_SET_NAME(thread_name.c_str());
1598

1599
        // set thread name as shown in Visual Studio
1600
        util::set_thread_name(thread_name.c_str());
1601

1602
#if defined(HPX_HAVE_APEX)
×
1603
        // not registering helper threads - for now
×
1604
        //util::external_timer::register_thread(thread_name.c_str());
1605
#endif
1606

×
1607
        wait_finalize();
×
1608

×
1609
        // stop main thread pool
1610
        main_pool_->stop();
×
1611
    }
×
1612

1613
    int runtime::wait()
1614
    {
32✔
1615
        LRT_(info).format("runtime_local: about to enter wait state");
1616

32✔
1617
        // start the wait_helper in a separate thread
1618
        std::mutex mtx;
1619
        std::condition_variable cond;
32✔
1620
        bool running = false;
1621

32✔
1622
        std::thread t(hpx::bind(&runtime::wait_helper, this, std::ref(mtx),
1623
            std::ref(cond), std::ref(running)));
1624

1625
        // wait for the thread to run
32✔
1626
        {
32✔
1627
            std::unique_lock<std::mutex> lk(mtx);
32✔
1628
            // NOLINTNEXTLINE(bugprone-infinite-loop)
1629
            while (!running)      //-V776 //-V1044
32✔
1630
                cond.wait(lk);    //-V1089
32✔
1631
        }
1632

1633
        // use main thread to drive main thread pool
1634
        main_pool_->thread_run(0);
32✔
1635

32✔
1636
        // block main thread
32✔
1637
        t.join();
1638

32✔
1639
        thread_manager_->wait();
32✔
1640

1641
        LRT_(info).format("runtime_local: exiting wait state");
1642
        return result_;
32✔
1643
    }
1644

1645
    ///////////////////////////////////////////////////////////////////////////
1646
    // First half of termination process: stop thread manager,
1647
    // schedule a task managed by timer_pool to initiate second part
×
1648
    void runtime::stop(bool blocking)
1649
    {
1650
        LRT_(warning).format("runtime_local: about to stop services");
1651

×
1652
        // execute all on_exit functions whenever the first thread calls this
1653
        this->runtime::stopping();
×
1654

1655
        // stop runtime_local services (threads)
1656
        thread_manager_->stop(false);    // just initiate shutdown
×
1657

1658
#ifdef HPX_HAVE_APEX
×
1659
        util::external_timer::finalize();
1660
#endif
1661

×
1662
        if (threads::get_self_ptr())
×
1663
        {
1664
            // schedule task on separate thread to execute stop_helper() below
×
1665
            // this is necessary as this function (stop()) might have been called
1666
            // from a HPX thread, so it would deadlock by waiting for the thread
×
1667
            // manager
1668
            std::mutex mtx;
×
1669
            std::condition_variable cond;
1670
            std::unique_lock<std::mutex> l(mtx);
1671

1672
            std::thread t(hpx::bind(&runtime::stop_helper, this, blocking,
1673
                std::ref(cond), std::ref(mtx)));
×
1674
            cond.wait(l);    //-V1089
1675

×
1676
            t.join();
1677
        }
1678
        else
1679
        {
1680
            thread_manager_->stop(blocking);    // wait for thread manager
×
1681

1682
            deinit_global_data();
1683

×
1684
            // this disables all logging from the main thread
1685
            deinit_tss_helper("main-thread", 0);
1686

×
1687
            LRT_(info).format("runtime_local: stopped all services");
1688
        }
1689

×
1690
#ifdef HPX_HAVE_TIMER_POOL
1691
        LTM_(info).format("stop: stopping timer pool");
×
1692
        timer_pool_->stop();
1693
        if (blocking)
1694
        {
×
1695
            timer_pool_->join();
1696
            timer_pool_->clear();
×
1697
        }
1698
#endif
×
1699
#ifdef HPX_HAVE_IO_POOL
1700
        LTM_(info).format("stop: stopping io pool");
1701
        io_pool_->stop();
1702
        if (blocking)
1703
        {
×
1704
            io_pool_->join();
1705
            io_pool_->clear();
×
1706
        }
1707
#endif
1708
    }
1709

1710
    // Second step in termination: shut down all services. This gets executed as
×
1711
    // a task in the timer_pool io_service and not as a HPX thread!
1712
    void runtime::stop_helper(
×
1713
        bool blocking, std::condition_variable& cond, std::mutex& mtx) const
1714
    {
×
1715
        // wait for thread manager to exit
1716
        thread_manager_->stop(blocking);    // wait for thread manager
1717

32✔
1718
        deinit_global_data();
1719

32✔
1720
        // this disables all logging from the main thread
32✔
1721
        deinit_tss_helper("main-thread", 0);
1722

1723
        LRT_(info).format("runtime_local: stopped all services");
×
1724

1725
        std::lock_guard<std::mutex> l(mtx);
×
1726
        cond.notify_all();    // we're done now
1727
    }
1728

5✔
1729
    int runtime::suspend()
1730
    {
5✔
1731
        LRT_(info).format("runtime_local: about to suspend runtime");
1732

1733
        if (state_.load() == hpx::state::sleeping)
35✔
1734
        {
1735
            return 0;
35✔
1736
        }
1737

1738
        if (state_.load() != hpx::state::running)
1739
        {
×
1740
            HPX_THROW_EXCEPTION(hpx::error::invalid_status, "runtime::suspend",
1741
                "Can only suspend runtime from running state");
1742
        }
1743

1744
        thread_manager_->suspend();
×
1745

1746
#ifdef HPX_HAVE_TIMER_POOL
×
1747
        timer_pool_->wait();
1748
#endif
1749
#ifdef HPX_HAVE_IO_POOL
1750
        io_pool_->wait();
×
1751
#endif
×
1752

1753
        set_state(hpx::state::sleeping);
1754

×
1755
        return 0;
1756
    }
×
1757

1758
    int runtime::resume()
1759
    {
1760
        LRT_(info).format("runtime_local: about to resume runtime");
1761

×
1762
        if (state_.load() == hpx::state::running)
×
1763
        {
1764
            return 0;
1765
        }
×
1766

×
1767
        if (state_.load() != hpx::state::sleeping)
1768
        {
×
1769
            HPX_THROW_EXCEPTION(hpx::error::invalid_status, "runtime::resume",
1770
                "Can only resume runtime from suspended state");
1771
        }
1772

1773
        thread_manager_->resume();
1774

×
1775
        set_state(hpx::state::running);
1776

×
1777
        return 0;
1778
    }
1779

64✔
1780
    int runtime::finalize(double /*shutdown_timeout*/)
1781
    {
64✔
1782
        notify_finalize();
1783
        return 0;
64✔
1784
    }
64✔
1785

1786
    bool runtime::is_networking_enabled()
1787
    {
×
1788
        return false;
×
1789
    }
1790

1791
    hpx::threads::threadmanager& runtime::get_thread_manager()
64✔
1792
    {
1793
        return *thread_manager_;
1794
    }
31✔
1795

1796
    std::string runtime::here() const
1797
    {
31✔
1798
        return "127.0.0.1";
1799
    }
1800

31✔
1801
    ///////////////////////////////////////////////////////////////////////////
31✔
1802
    bool runtime::report_error(std::size_t num_thread,
1803
        std::exception_ptr const& e, bool /*terminate_all*/)
31✔
1804
    {
31✔
1805
        // call thread-specific user-supplied on_error handler
1806
        bool report_exception = true;
1807
        if (on_error_func_)
1808
        {
×
1809
            report_exception = on_error_func_(num_thread, e);
1810
        }
1811

×
1812
        // Early and late exceptions, errors outside HPX-threads
1813
        if (!threads::get_self_ptr() ||
1814
            !threads::threadmanager_is(hpx::state::running))
×
1815
        {
×
1816
            // report the error to the local console
1817
            if (report_exception)
×
1818
            {
×
1819
                detail::report_exception_and_continue(e);
1820
            }
1821

×
1822
            // store the exception to be able to rethrow it later
1823
            {
×
1824
                std::lock_guard<std::mutex> l(mtx_);
1825
                exception_ = e;
1826
            }
1827

96✔
1828
            notify_finalize();
1829
            stop(false);
1830

1831
            return report_exception;
1832
        }
1833

1834
        return report_exception;
1835
    }
1836

1837
    bool runtime::report_error(std::exception_ptr const& e, bool terminate_all)
1838
    {
96✔
1839
        return report_error(hpx::get_worker_thread_num(), e, terminate_all);
1840
    }
96✔
1841

96✔
1842
    void runtime::rethrow_exception()
1843
    {
96✔
1844
        if (state_.load() > hpx::state::running)
96✔
1845
        {
96✔
1846
            std::lock_guard<std::mutex> l(mtx_);
96✔
1847
            if (exception_)
1848
            {
1849
                std::exception_ptr const e = exception_;
96✔
1850
                exception_ = std::exception_ptr();
×
1851
                std::rethrow_exception(e);
1852
            }
219✔
1853
        }
1854
    }
1855

1856
    ///////////////////////////////////////////////////////////////////////////
1857
    int runtime::run(hpx::function<hpx_main_function_type> const& func)
1858
    {
219✔
1859
        // start the main thread function
219✔
1860
        start(func);
1861

1862
        // now wait for everything to finish
219✔
1863
        wait();
1864
        stop();
1865

1866
        rethrow_exception();
1867
        return result_;
1868
    }
1869

1870
    ///////////////////////////////////////////////////////////////////////////
1871
    int runtime::run()
1872
    {
219✔
1873
        // start the main thread function
1874
        start();
1875

1876
        // now wait for everything to finish
1877
        int const result = wait();
1878
        stop();
1879

219✔
1880
        rethrow_exception();
1881
        return result;
1882
    }
1883

1884
    util::thread_mapper& runtime::get_thread_mapper() const
219✔
1885
    {
1886
        return *thread_support_;
219✔
1887
    }
1888

1889
    ///////////////////////////////////////////////////////////////////////////
219✔
1890
    threads::policies::callback_notifier runtime::get_notification_policy(
1891
        char const* prefix, runtime_local::os_thread_type type)
1892
    {
1893
        using report_error_t =
1894
            bool (runtime::*)(std::size_t, std::exception_ptr const&, bool);
1895

219✔
1896
        using placeholders::_1;
1897
        using placeholders::_2;
1898
        using placeholders::_3;
1899
        using placeholders::_4;
1900

1901
        notification_policy_type notifier;
1902

1903
        notifier.add_on_start_thread_callback(
219✔
1904
            hpx::bind(&runtime::init_tss_helper, this, prefix, type, _1, _2, _3,
1905
                _4, false));
×
1906
        notifier.add_on_stop_thread_callback(
1907
            hpx::bind(&runtime::deinit_tss_helper, this, prefix, _1));
1908
        notifier.set_on_error_callback(
1909
            hpx::bind(static_cast<report_error_t>(&runtime::report_error), this,
1910
                _1, _2, true));
219✔
1911

1912
        return notifier;
1913
    }
1914

1915
    void runtime::init_tss_helper(char const* context,
1916
        runtime_local::os_thread_type type, std::size_t local_thread_num,
×
1917
        std::size_t global_thread_num, char const* pool_name,
1918
        char const* postfix, bool service_thread) const
1919
    {
×
1920
        error_code ec(throwmode::lightweight);
1921
        return init_tss_ex(context, type, local_thread_num, global_thread_num,
×
1922
            pool_name, postfix, service_thread, ec);
×
1923
    }
1924

1925
    void runtime::init_tss_ex(char const* context,
1926
        runtime_local::os_thread_type type, std::size_t local_thread_num,
1927
        std::size_t global_thread_num, char const* pool_name,
1928
        char const* postfix, bool service_thread, error_code& ec) const
1929
    {
1930
        // set the thread's name, if it's not already set
1931
        HPX_ASSERT(detail::thread_name().empty());
1932

1933
        std::string fullname;
1934
        fullname += context;
1935
        if (postfix && *postfix)
1936
            fullname += postfix;
1937

1938
#if defined(HPX_GCC_VERSION) && HPX_GCC_VERSION >= 110000
1939
#pragma GCC diagnostic push
1940
#pragma GCC diagnostic ignored "-Wrestrict"
219✔
1941
#endif
1942
        fullname += "#" + std::to_string(global_thread_num);
220✔
1943
#if defined(HPX_GCC_VERSION) && HPX_GCC_VERSION >= 110000
1944
#pragma GCC diagnostic pop
1945
#endif
220✔
1946

1947
        detail::thread_name() = HPX_MOVE(fullname);
1948

220✔
1949
        char const* name = detail::thread_name().c_str();
1950

×
1951
        // initialize thread mapping for external libraries (i.e. PAPI)
1952
        thread_support_->register_thread(name, type);
1953

1954
        // register this thread with any possibly active Intel tool
220✔
1955
        HPX_ITT_THREAD_SET_NAME(name);
1956

1957
        // set thread name as shown in Visual Studio
220✔
1958
        util::set_thread_name(name);
220✔
1959

1960
#if defined(HPX_HAVE_APEX)
×
1961
        if (std::strstr(name, "worker") != nullptr)
1962
            util::external_timer::register_thread(name);
×
1963
#endif
1964

×
1965
        // call thread-specific user-supplied on_start handler
×
1966
        if (on_start_func_)
1967
        {
×
1968
            on_start_func_(
1969
                local_thread_num, global_thread_num, pool_name, context);
×
1970
        }
1971

×
1972
        // if this is a service thread, set its service affinity
1973
        if (service_thread)
×
1974
        {
×
1975
            // FIXME: We don't set the affinity of the service threads on BG/Q,
1976
            // as this is causing a hang (needs to be investigated)
×
1977
#if !defined(__bgq__)
1978
            threads::mask_cref_type used_processing_units =
×
1979
                thread_manager_->get_used_processing_units();
1980

×
1981
            // --hpx:bind=none  should disable all affinity definitions
1982
            if (threads::any(used_processing_units))
×
1983
            {
×
1984
                this->topology_.set_thread_affinity_mask(
1985
                    this->topology_.get_service_affinity_mask(
×
1986
                        used_processing_units),
1987
                    ec);
1✔
1988

1989
                // comment this out for now as on CircleCI this is causing
1✔
1990
                // unending grief
1991
                //if (ec)
1✔
1992
                //{
1✔
1993
                //    HPX_THROW_EXCEPTION(hpx::error::kernel_error,
1994
                //        "runtime::init_tss_ex",
1✔
1995
                //        "failed to set thread affinity mask ({}) for service "
1996
                //        "thread: {}",
139✔
1997
                //        hpx::threads::to_string(used_processing_units),
1998
                //        detail::thread_name());
1999
                //}
2000
            }
139✔
2001
#endif
×
2002
        }
2003
    }
2004

139✔
2005
    void runtime::deinit_tss_helper(
138✔
2006
        char const* context, std::size_t global_thread_num) const
2007
    {
1✔
2008
        threads::reset_continuation_recursion_count();
1✔
2009

2010
        // call thread-specific user-supplied on_stop handler
×
2011
        if (on_stop_func_)
2012
        {
2013
            on_stop_func_(global_thread_num, global_thread_num, "", context);
2014
        }
2015

2016
        // reset PAPI support
×
2017
        thread_support_->unregister_thread();
2018

2019
        // reset thread local storage
×
2020
        detail::thread_name().clear();
2021
    }
2022

×
2023
    void runtime::add_pre_startup_function(startup_function_type f)
2024
    {
2025
        if (!f.empty())
2026
        {
×
2027
            std::lock_guard<std::mutex> l(mtx_);
2028
            pre_startup_functions_.push_back(HPX_MOVE(f));
2029
        }
2030
    }
1✔
2031

2032
    void runtime::add_startup_function(startup_function_type f)
2✔
2033
    {
1✔
2034
        if (!f.empty())
1✔
2035
        {
2036
            std::lock_guard<std::mutex> l(mtx_);
2037
            startup_functions_.push_back(HPX_MOVE(f));
2038
        }
2039
    }
2040

×
2041
    void runtime::add_pre_shutdown_function(shutdown_function_type f)
2042
    {
2043
        if (!f.empty())
×
2044
        {
2045
            std::lock_guard<std::mutex> l(mtx_);
2046
            pre_shutdown_functions_.push_back(HPX_MOVE(f));
2047
        }
×
2048
    }
2049

2050
    void runtime::add_shutdown_function(shutdown_function_type f)
×
2051
    {
2052
        if (!f.empty())
2053
        {
2054
            std::lock_guard<std::mutex> l(mtx_);
×
2055
            shutdown_functions_.push_back(HPX_MOVE(f));
2056
        }
2057
    }
×
2058

×
2059
    hpx::util::io_service_pool* runtime::get_thread_pool(char const* name)
2060
    {
2061
        HPX_ASSERT(name != nullptr);
221✔
2062
#ifdef HPX_HAVE_IO_POOL
2063
        if (0 == std::strncmp(name, "io", 2))
221✔
2064
            return io_pool_.get();
221✔
2065
#endif
2066
#ifdef HPX_HAVE_TIMER_POOL
2067
        if (0 == std::strncmp(name, "timer", 5))
×
2068
            return timer_pool_.get();
2069
#endif
2070
        if (0 == std::strncmp(name, "main", 4))    //-V112
221✔
2071
            return main_pool_.get();
2072

2073
        HPX_THROW_EXCEPTION(hpx::error::bad_parameter,
×
2074
            "runtime::get_thread_pool", "unknown thread pool requested: {}",
2075
            name);
×
2076
    }
×
2077

2078
    /// Register an external OS-thread with HPX
×
2079
    bool runtime::register_thread(char const* name,
2080
        std::size_t global_thread_num, bool service_thread, error_code& ec)
2081
    {
2082
        std::string thread_name(name);
2083
        thread_name += "-thread";
2084

×
2085
        init_tss_ex(thread_name.c_str(),
2086
            runtime_local::os_thread_type::custom_thread, global_thread_num,
2087
            global_thread_num, "", nullptr, service_thread, ec);
2088

2089
        return !ec ? true : false;
1✔
2090
    }
2091

1✔
2092
    /// Unregister an external OS-thread with HPX
1✔
2093
    bool runtime::unregister_thread()
2094
    {
×
2095
        deinit_tss_helper(
2096
            detail::thread_name().c_str(), hpx::get_worker_thread_num());
2097
        return true;
2098
    }
2099

2100
    // Access data for a given OS thread that was previously registered by
1✔
2101
    // \a register_thread. This function must be called from a thread that was
2102
    // previously registered with the runtime.
2103
    runtime_local::os_thread_data runtime::get_os_thread_data(
465✔
2104
        std::string const& label) const
2105
    {
465✔
2106
        return thread_support_->get_os_thread_data(label);
465✔
2107
    }
2108

×
2109
    /// Enumerate all OS threads that have registered with the runtime.
2110
    bool runtime::enumerate_os_threads(
2111
        hpx::function<bool(os_thread_data const&)> const& f) const
2112
    {
2113
        return thread_support_->enumerate_os_threads(f);
2114
    }
465✔
2115

2116
    ///////////////////////////////////////////////////////////////////////////
2117
    threads::policies::callback_notifier get_notification_policy(
×
2118
        char const* prefix)
2119
    {
×
2120
        return get_runtime().get_notification_policy(
×
2121
            prefix, runtime_local::os_thread_type::worker_thread);
2122
    }
×
2123

2124
    std::uint32_t get_locality_id(error_code& ec)
2125
    {
2126
        runtime const* rt = get_runtime_ptr();
2127
        if (nullptr == rt || rt->get_state() == state::invalid)
2128
        {
×
2129
            // same as naming::invalid_locality_id
2130
            return ~static_cast<std::uint32_t>(0);
2131
        }
2132

2✔
2133
        return rt->get_locality_id(ec);
2134
    }
2135

2136
    std::size_t get_num_worker_threads()
2✔
2137
    {
2✔
2138
        runtime const* rt = get_runtime_ptr();
2139
        if (nullptr == rt)
2✔
2140
        {
2141
            HPX_THROW_EXCEPTION(hpx::error::invalid_status,
2✔
2142
                "hpx::get_num_worker_threads",
2143
                "the runtime system has not been initialized yet");
×
2144
        }
2145

×
2146
        return rt->get_num_worker_threads();
2147
    }
2148

2✔
2149
    /// \brief Return the number of localities which are currently registered
2150
    ///        for the running application.
2151
    std::uint32_t get_num_localities(hpx::launch::sync_policy, error_code& ec)
2152
    {
2153
        runtime const* rt = get_runtime_ptr();
2154
        if (nullptr == rt)
2155
        {
2156
            HPX_THROW_EXCEPTION(hpx::error::invalid_status,
2157
                "hpx::get_num_localities",
2158
                "the runtime system has not been initialized yet");
2159
        }
2160

2161
        return rt->get_num_localities(hpx::launch::sync, ec);
2162
    }
2163

2164
    std::uint32_t get_initial_num_localities()
2165
    {
2166
        runtime const* rt = get_runtime_ptr();
2167
        if (nullptr == rt)
2168
        {
2169
            HPX_THROW_EXCEPTION(hpx::error::invalid_status,
2170
                "hpx::get_initial_num_localities",
2171
                "the runtime system has not been initialized yet");
2172
        }
2173

2174
        return rt->get_initial_num_localities();
2175
    }
2176

2177
    hpx::future<std::uint32_t> get_num_localities()
2178
    {
2179
        runtime const* rt = get_runtime_ptr();
2180
        if (nullptr == rt)
2181
        {
2182
            HPX_THROW_EXCEPTION(hpx::error::invalid_status,
2183
                "hpx::get_num_localities",
2184
                "the runtime system has not been initialized yet");
2185
        }
2186

2187
        return rt->get_num_localities();
2188
    }
2189

2190
    namespace threads {
2191

2192
        char const* get_stack_size_name(std::ptrdiff_t size)
2193
        {
2194
            auto size_enum = thread_stacksize::unknown;
2195

2196
            hpx::util::runtime_configuration const& rtcfg = hpx::get_config();
2197
            if (rtcfg.get_stack_size(thread_stacksize::small_) == size)
2198
                size_enum = thread_stacksize::small_;
2199
            else if (rtcfg.get_stack_size(thread_stacksize::medium) == size)
2200
                size_enum = thread_stacksize::medium;
2201
            else if (rtcfg.get_stack_size(thread_stacksize::large) == size)
2202
                size_enum = thread_stacksize::large;
2203
            else if (rtcfg.get_stack_size(thread_stacksize::huge) == size)
2204
                size_enum = thread_stacksize::huge;
2205
            else if (rtcfg.get_stack_size(thread_stacksize::nostack) == size)
2206
                size_enum = thread_stacksize::nostack;
2207

2208
            return get_stack_size_enum_name(size_enum);
2209
        }
2210
    }    // namespace threads
2211
}    // 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