• 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

57.99
/libs/full/runtime_distributed/src/server/runtime_support_server.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

10
#include <hpx/actions_base/plain_action.hpp>
11
#include <hpx/agas/addressing_service.hpp>
12
#include <hpx/assert.hpp>
13
#include <hpx/async_distributed/continuation.hpp>
14
#include <hpx/command_line_handling/command_line_handling.hpp>
15
#include <hpx/command_line_handling/late_command_line_handling.hpp>
16
#include <hpx/command_line_handling/parse_command_line.hpp>
17
#include <hpx/components_base/agas_interface.hpp>
18
#include <hpx/components_base/component_type.hpp>
19
#include <hpx/components_base/server/create_component.hpp>
20
#include <hpx/modules/async_combinators.hpp>
21
#include <hpx/modules/async_distributed.hpp>
22
#include <hpx/modules/errors.hpp>
23
#include <hpx/modules/execution_base.hpp>
24
#include <hpx/modules/filesystem.hpp>
25
#include <hpx/modules/format.hpp>
26
#include <hpx/modules/futures.hpp>
27
#include <hpx/modules/ini.hpp>
28
#include <hpx/modules/logging.hpp>
29
#include <hpx/modules/prefix.hpp>
30
#include <hpx/modules/runtime_configuration.hpp>
31
#include <hpx/modules/runtime_local.hpp>
32
#include <hpx/modules/serialization.hpp>
33
#include <hpx/modules/string_util.hpp>
34
#include <hpx/modules/synchronization.hpp>
35
#include <hpx/modules/thread_support.hpp>
36
#include <hpx/modules/threadmanager.hpp>
37
#include <hpx/modules/timing.hpp>
38
#include <hpx/modules/type_support.hpp>
39
#include <hpx/performance_counters/counters.hpp>
40
#include <hpx/plugin_factories/binary_filter_factory_base.hpp>
41
#include <hpx/plugin_factories/message_handler_factory_base.hpp>
42
#include <hpx/runtime_components/console_logging.hpp>
43
#include <hpx/runtime_distributed.hpp>
44
#include <hpx/runtime_distributed/find_localities.hpp>
45
#include <hpx/runtime_distributed/runtime_fwd.hpp>
46
#include <hpx/runtime_distributed/server/runtime_support.hpp>
47
#include <hpx/runtime_distributed/stubs/runtime_support.hpp>
48

49
#ifdef HPX_HAVE_LIB_MPI_BASE
50
#include <hpx/modules/mpi_base.hpp>
51
#endif
52

53
#include <algorithm>
54
#include <cstddef>
55
#include <cstdint>
56
#include <exception>
57
#include <iomanip>
58
#include <iostream>
59
#include <map>
60
#include <memory>
61
#include <mutex>
62
#include <set>
63
#include <sstream>
64
#include <string>
65
#include <system_error>
66
#include <thread>
67
#include <utility>
68
#include <vector>
69

70
#include <hpx/config/warnings_prefix.hpp>
71

72
///////////////////////////////////////////////////////////////////////////////
73
// Serialization support for the runtime_support actions
74
HPX_REGISTER_ACTION_ID(
75
    hpx::components::server::runtime_support::load_components_action,
76
    load_components_action, hpx::actions::load_components_action_id)
77
HPX_REGISTER_ACTION_ID(
78
    hpx::components::server::runtime_support::call_startup_functions_action,
79
    call_startup_functions_action,
192✔
80
    hpx::actions::call_startup_functions_action_id)
81
HPX_REGISTER_ACTION_ID(
82
    hpx::components::server::runtime_support::call_shutdown_functions_action,
192✔
83
    call_shutdown_functions_action,
84
    hpx::actions::call_shutdown_functions_action_id)
85
HPX_REGISTER_ACTION_ID(
86
    hpx::components::server::runtime_support::shutdown_action, shutdown_action,
195✔
87
    hpx::actions::shutdown_action_id)
88
HPX_REGISTER_ACTION_ID(
89
    hpx::components::server::runtime_support::shutdown_all_action,
90
    shutdown_all_action, hpx::actions::shutdown_all_action_id)
195✔
91
HPX_REGISTER_ACTION_ID(
92
    hpx::components::server::runtime_support::terminate_action,
93
    terminate_action, hpx::actions::terminate_action_id)
192✔
94
HPX_REGISTER_ACTION_ID(
95
    hpx::components::server::runtime_support::terminate_all_action,
96
    terminate_all_action, hpx::actions::terminate_all_action_id)
192✔
97
HPX_REGISTER_ACTION_ID(
98
    hpx::components::server::runtime_support::get_config_action,
99
    get_config_action, hpx::actions::get_config_action_id)
192✔
100
HPX_REGISTER_ACTION_ID(
101
    hpx::components::server::runtime_support::garbage_collect_action,
102
    garbage_collect_action, hpx::actions::garbage_collect_action_id)
192✔
103
HPX_REGISTER_ACTION_ID(
104
    hpx::components::server::runtime_support::create_performance_counter_action,
105
    create_performance_counter_action,
192✔
106
    hpx::actions::create_performance_counter_action_id)
107
HPX_REGISTER_ACTION_ID(hpx::components::server::runtime_support::
108
                           remove_from_connection_cache_action,
192✔
109
    remove_from_connection_cache_action,
110
    hpx::actions::remove_from_connection_cache_action_id)
111
#if defined(HPX_HAVE_NETWORKING)
112
HPX_REGISTER_ACTION_ID(
192✔
113
    hpx::components::server::runtime_support::dijkstra_termination_action,
114
    dijkstra_termination_action, hpx::actions::dijkstra_termination_action_id)
115
#endif
116

117
///////////////////////////////////////////////////////////////////////////////
198✔
118
HPX_DEFINE_COMPONENT_NAME(
119
    hpx::components::server::runtime_support, hpx_runtime_support)
120
HPX_DEFINE_GET_COMPONENT_TYPE_STATIC(hpx::components::server::runtime_support,
121
    to_int(hpx::components::component_enum_type::runtime_support))
122

123
namespace hpx {
×
124
    // helper function to stop evaluating counters during shutdown
125
    void stop_evaluating_counters(bool terminate = false);
36✔
126
}    // namespace hpx
127

128
///////////////////////////////////////////////////////////////////////////////
129
namespace hpx { namespace components { namespace server {
130
    ///////////////////////////////////////////////////////////////////////////
131
    runtime_support::runtime_support(hpx::util::runtime_configuration& cfg)
132
      : stop_called_(false)
133
      , stop_done_(false)
134
      , terminated_(false)
135
      , main_thread_id_(std::this_thread::get_id())
136
      , shutdown_all_invoked_(false)
32✔
137
#if defined(HPX_HAVE_NETWORKING)
32✔
138
      , dijkstra_mtx_()
32✔
139
      , dijkstra_cond_()
32✔
140
      , dijkstra_color_(false)
32✔
141
#endif
142
      , p_mtx_()
143
      , plugins_()
144
      , modules_(cfg.modules())
145
      , static_modules_()
32✔
146
    {
147
    }
148

149
    // function to be called during shutdown
32✔
150
    // Action: shut down this runtime system instance
32✔
151
    void runtime_support::shutdown(
152
        double timeout, hpx::id_type const& respond_to)
32✔
153
    {
154
        // initiate system shutdown
155
        stop(timeout, respond_to, false);
156
    }
3✔
157

158
    // function to be called to terminate this locality immediately
159
    void runtime_support::terminate(hpx::id_type const& respond_to)
160
    {
3✔
161
#if !defined(HPX_COMPUTE_DEVICE_CODE)
3✔
162
        // push pending logs
163
        components::cleanup_logging();
164

×
165
        if (respond_to)
166
        {
167
            // respond synchronously
168
            using void_lco_type = lcos::base_lco_with_value<void>;
×
169
            using action_type = void_lco_type::set_event_action;
170

171
            naming::address addr;
172
            if (agas::is_local_address_cached(respond_to, addr))
173
            {
174
                // execute locally, action is executed immediately as it is
175
                // a direct_action
176
                hpx::detail::post_l<action_type>(respond_to, HPX_MOVE(addr));
×
177
            }
×
178
#if defined(HPX_HAVE_NETWORKING)
179
            else
180
            {
181
                // apply remotely, parcel is sent synchronously
182
                hpx::detail::post_r_sync<action_type>(
183
                    HPX_MOVE(addr), respond_to);
184
            }
185
#endif
186
        }
187
#else
188
        HPX_ASSERT(false);
189
        HPX_UNUSED(respond_to);
190
#endif
191
        std::abort();
192
    }
193
}}}    // namespace hpx::components::server
194

195
///////////////////////////////////////////////////////////////////////////////
196
namespace hpx { namespace components { namespace server {
×
197

198
    // initiate system shutdown for all localities
199
    void invoke_shutdown_functions(
200
        std::vector<hpx::id_type> const& localities, bool pre_shutdown)
201
    {
202
#if !defined(HPX_COMPUTE_DEVICE_CODE)
203
        std::vector<hpx::future<void>> results;
204
        results.reserve(localities.size());
58✔
205
        for (auto const& l : localities)
206
        {
207
            using call_shutdown_functions_action = hpx::components::server::
208
                runtime_support::call_shutdown_functions_action;
58✔
209
            results.push_back(
58✔
210
                hpx::async(call_shutdown_functions_action(), l, pre_shutdown));
122✔
211
        }
212
        hpx::wait_all(results);
213
#else
214
        HPX_ASSERT(false);
215
        HPX_UNUSED(localities);
64✔
216
        HPX_UNUSED(pre_shutdown);
217
#endif
218
    }
219

220
    ///////////////////////////////////////////////////////////////////////////
221
#if defined(HPX_HAVE_NETWORKING)
222
    void runtime_support::dijkstra_make_black()
223
    {
58✔
224
        // Rule 1: A machine sending a message makes itself black.
225
        if (!dijkstra_color_)
226
        {
227
            dijkstra_color_ = true;
768✔
228
        }
229
    }
230

768✔
231
    void runtime_support::send_dijkstra_termination_token(
768✔
232
        [[maybe_unused]] std::uint32_t target_locality_id,
768✔
233
        [[maybe_unused]] std::uint32_t initiating_locality_id,
234
        [[maybe_unused]] std::uint32_t num_localities,
24✔
235
        [[maybe_unused]] bool dijkstra_token)
236
    {
237
        // First wait for this locality to become passive. We do this by
238
        // periodically checking the number of still running threads.
239
        //
240
        // Rule 0: When active, machine nr.i + 1 keeps the token; when passive,
241
        // it hands over the token to machine nr.i.
242
        threads::threadmanager& tm =
243
            hpx::applier::get_applier().get_thread_manager();
244

245
        // if the threading system is not finished running after a small amount
246
        // of time we assume that more work has to be done
24✔
247
        bool const passive = tm.wait_for(std::chrono::milliseconds(10));
248
        tm.cleanup_terminated(true);
249

250
        // Now this locality has become passive, thus we can send the token
24✔
251
        // to the next locality.
24✔
252
        //
253
        // Rule 2: When machine nr.i + 1 propagates the probe, it hands over a
254
        // black token to machine nr.i if it is black itself, whereas while
255
        // being white it leaves the color of the token unchanged.
256
        {
257
            if (!passive || dijkstra_color_)
258
                dijkstra_token = true;
259

260
            // Rule 5: Upon transmission of the token to machine nr.i, machine
24✔
261
            // nr.i + 1 becomes white.
24✔
262
            dijkstra_color_ = false;
6✔
263
        }
264

265
#if !defined(HPX_COMPUTE_DEVICE_CODE)
266
        hpx::latch l(2);
24✔
267
        hpx::id_type const id(
268
            naming::get_id_from_locality_id(target_locality_id));
269
        hpx::post_cb<dijkstra_termination_action>(
270
            id,
271
            [&l](std::error_code const&, parcelset::parcel const&) {
272
                l.count_down(1);
273
            },
274
            initiating_locality_id, num_localities, dijkstra_token);
275
        l.arrive_and_wait();
24✔
276
#else
24✔
277
        HPX_ASSERT(false);
24✔
278
#endif
279
    }
24✔
280

281
    // invoked during termination detection
282
    void runtime_support::dijkstra_termination(
283
        std::uint32_t initiating_locality_id, std::uint32_t num_localities,
24✔
284
        bool dijkstra_token)
285
    {
286
        applier::applier& appl = hpx::applier::get_applier();
24✔
287
        agas::addressing_service& agas_client = naming::get_agas_client();
288

289
        agas_client.start_shutdown();
290

24✔
291
        parcelset::parcelhandler& ph = appl.get_parcel_handler();
24✔
292
        ph.flush_parcels();
293

24✔
294
        std::uint32_t locality_id = get_locality_id();
295

24✔
296
        if (initiating_locality_id == locality_id)
24✔
297
        {
298
            // we received the token after a full circle
24✔
299
            if (dijkstra_token)
300
            {
24✔
301
                dijkstra_color_ = true;    // unsuccessful termination
302
            }
303

12✔
304
            // We need the lock here to ensure the mutual exclusion of
305
            // hpx::latch::count_down and and hpx::latch::~latch
6✔
306
            std::lock_guard<dijkstra_mtx_type> l(dijkstra_mtx_);
6✔
307
            dijkstra_cond_->count_down(1);
308
            return;
309
        }
12✔
310

12✔
311
        if (0 == locality_id)
312
            locality_id = num_localities;
313

12✔
314
        send_dijkstra_termination_token(locality_id - 1, initiating_locality_id,
315
            num_localities, dijkstra_token);
316
    }
12✔
317
#endif
318

319
    // Kick off termination detection, this is modeled after Dijkstra's paper:
320
    // http://www.cs.mcgill.ca/~lli22/575/termination3.pdf.
321
    std::size_t runtime_support::dijkstra_termination_detection(
322
        std::vector<hpx::id_type> const& locality_ids)
323
    {
58✔
324
#if defined(HPX_HAVE_NETWORKING)
325
        std::uint32_t num_localities =
326
            static_cast<std::uint32_t>(locality_ids.size());
327
        if (num_localities == 1)
328
#endif
58✔
329

58✔
330
        {
331
            // While no real distributed termination detection has to be
332
            // performed, we should still wait for the thread-queues to drain.
333
            applier::applier& appl = hpx::applier::get_applier();
334
            threads::threadmanager& tm = appl.get_thread_manager();
335

52✔
336
            tm.wait();
52✔
337
            tm.cleanup_terminated(true);
338

52✔
339
            HPX_UNUSED(locality_ids);
52✔
340
            return 0;
341
        }
342

52✔
343
#if defined(HPX_HAVE_NETWORKING)
344
        std::uint32_t initiating_locality_id = get_locality_id();
345

346
        // send token to previous node
6✔
347
        std::uint32_t target_id = initiating_locality_id;
348
        if (0 == target_id)
349
            target_id = num_localities;
350

6✔
351
        std::size_t count = 0;    // keep track of number of trials
352

353
        {
354
            do
355
            {
356
                LRT_(info).format(
357
                    "runtime_support::dijkstra_termination_detection: "
358
                    "initiates a probe by making itself white and sending a "
359
                    "white token to next machine.");
360

6✔
361
                // Rule 4: Machine nr.0 initiates a probe by making itself white
362
                // and sending a white token to machine nr.N - 1.
363
                dijkstra_color_ = false;    // start off with white
12✔
364
                dijkstra_cond_ = std::make_unique<hpx::latch>(2);
365

366
                {
367
                    send_dijkstra_termination_token(target_id - 1,
368
                        initiating_locality_id, num_localities,
369
                        dijkstra_color_);
370

12✔
371
                    LRT_(info).format(
24✔
372
                        "runtime_support::dijkstra_termination_detection: "
373
                        "wait for token to come back to us.");
374

375
                    // wait for token to come back to us
12✔
376
                    dijkstra_cond_->arrive_and_wait(1);
377
                }
12✔
378

379
                // Rule 3: After the completion of an unsuccessful probe, machine
12✔
380
                // nr.0 initiates a next probe.
381

382
                ++count;
383

384
                if (dijkstra_color_)
12✔
385
                {
386
                    LRT_(info).format(
387
                        "runtime_support::dijkstra_termination_detection: "
388
                        "After the completion of an unsuccessful probe, "
389
                        "initiate next probe.");
390
                }
12✔
391

392
            } while (dijkstra_color_);
12✔
393

394
            // We need the lock here to ensure the mutual exclusion of
6✔
395
            // hpx::latch::count_down and and hpx::latch::~latch
396
            std::lock_guard<dijkstra_mtx_type> l(dijkstra_mtx_);
397
            dijkstra_cond_.reset();
398
        }
399

400
        return count;
12✔
401
#endif
402
    }
403

404
    ///////////////////////////////////////////////////////////////////////////
405
    void runtime_support::shutdown_all(double timeout)
6✔
406
    {
407
        if (find_here() != hpx::find_root_locality())
408
        {
409
            HPX_THROW_EXCEPTION(hpx::error::invalid_status,
410
                "runtime_support::shutdown_all",
29✔
411
                "shutdown_all should be invoked on the root locality only");
412
            return;
87✔
413
        }
414

×
415
        // make sure shutdown_all is invoked only once
416
        bool flag = false;
417
        if (!shutdown_all_invoked_.compare_exchange_strong(flag, true))
×
418
        {
419
            return;
420
        }
421

29✔
422
        LRT_(info).format(
29✔
423
            "runtime_support::shutdown_all: initializing application shutdown");
424

425
        applier::applier& appl = hpx::applier::get_applier();
426
        agas::addressing_service& agas_client = naming::get_agas_client();
427

29✔
428
        agas_client.start_shutdown();
429

430
        stop_evaluating_counters(true);
29✔
431

29✔
432
        // wake up suspended pus
433
        threads::threadmanager& tm = appl.get_thread_manager();
29✔
434
        tm.resume();
435

29✔
436
        std::vector<hpx::id_type> locality_ids = find_all_localities();
437
        std::size_t count = dijkstra_termination_detection(locality_ids);
438

29✔
439
        LRT_(info).format("runtime_support::shutdown_all: passed first "
29✔
440
                          "termination detection (count: {}).",
441
            count);
29✔
442

29✔
443
        // execute registered shutdown functions on all localities
444
        invoke_shutdown_functions(locality_ids, true);
29✔
445
        invoke_shutdown_functions(locality_ids, false);
446

447
        LRT_(info).format(
448
            "runtime_support::shutdown_all: invoked shutdown functions");
449

29✔
450
        // Do a second round of termination detection to synchronize with all
29✔
451
        // work that was triggered by the invocation of the shutdown
452
        // functions.
29✔
453
        count = dijkstra_termination_detection(locality_ids);
454

455
        LRT_(info).format("runtime_support::shutdown_all: passed second "
456
                          "termination detection (count: {}).",
457
            count);
458

29✔
459
        // Shut down all localities except the local one, we can't use
460
        // broadcast here as we have to handle the back parcel in a special
29✔
461
        // way.
462
        std::reverse(locality_ids.begin(), locality_ids.end());
463
        std::uint32_t locality_id = get_locality_id();
464
        std::vector<hpx::future<void>> lazy_actions;
465

466
        for (hpx::id_type const& id : locality_ids)
467
        {
29✔
468
            if (locality_id != naming::get_locality_id_from_id(id))
29✔
469
            {
29✔
470
                using components::stubs::runtime_support;
471
                lazy_actions.emplace_back(
61✔
472
                    runtime_support::shutdown_async(id, timeout));
473
            }
32✔
474
        }
475

476
        // wait for all localities to be stopped
3✔
477
        hpx::wait_all(lazy_actions);
6✔
478

479
        LRT_(info).format("runtime_support::shutdown_all: all localities have "
480
                          "been shut down");
481

482
        // Now make sure this local locality gets shut down as well.
483
        // There is no need to respond...
484
        stop(timeout, hpx::invalid_id, false);
29✔
485
    }
486

487
    ///////////////////////////////////////////////////////////////////////////
488
    // initiate system shutdown for all localities
489
    void runtime_support::terminate_all()
29✔
490
    {
29✔
491
        std::vector<naming::gid_type> locality_ids;
492
        naming::get_agas_client().get_localities(locality_ids);
493
        std::reverse(locality_ids.begin(), locality_ids.end());
494

×
495
        // Terminate all localities except the local one, we can't use
496
        // broadcast here as we have to handle the back parcel in a special
×
497
        // way.
×
498
        {
×
499
            std::uint32_t locality_id = get_locality_id();
500
            std::vector<hpx::future<void>> lazy_actions;
501

502
            for (naming::gid_type gid : locality_ids)
503
            {
504
                if (locality_id != naming::get_locality_id_from_gid(gid))
×
505
                {
×
506
                    using components::stubs::runtime_support;
507
                    hpx::id_type id(
×
508
                        gid, hpx::id_type::management_type::unmanaged);
509
                    lazy_actions.emplace_back(
×
510
                        runtime_support::terminate_async(id));
511
                }
512
            }
513

×
514
            // wait for all localities to be stopped
×
515
            hpx::wait_all(lazy_actions);
×
516
        }
517

518
        // now make sure this local locality gets terminated as well.
519
        terminate(hpx::invalid_id);    //good night
520
    }
521

×
522
    ///////////////////////////////////////////////////////////////////////////
523
    // Retrieve configuration information
524
    util::section runtime_support::get_config()
×
525
    {
526
        return *(get_runtime().get_config().get_section("application"));
527
    }
528

529
    ///////////////////////////////////////////////////////////////////////////
×
530
    /// \brief Force a garbage collection operation in the AGAS layer.
531
    void runtime_support::garbage_collect()
×
532
    {
533
        naming::get_agas_client().garbage_collect_non_blocking();
534
    }
535

536
    ///////////////////////////////////////////////////////////////////////////
×
537
    /// \brief Create the given performance counter instance.
538
    naming::gid_type runtime_support::create_performance_counter(
×
539
        performance_counters::counter_info const& info)
×
540
    {
541
        return performance_counters::detail::create_counter_local(info);
542
    }
543

×
544
    ///////////////////////////////////////////////////////////////////////////
545
    void runtime_support::delete_function_lists()
546
    {
×
547
        pre_startup_functions_.clear();
548
        startup_functions_.clear();
549
        pre_shutdown_functions_.clear();
550
        shutdown_functions_.clear();
32✔
551
    }
552

553
    void runtime_support::tidy()
554
    {
555
        // Only after releasing the components we are allowed to release
556
        // the modules. This is done in reverse order of loading.
32✔
557
        plugins_.clear();    // unload all plugins
558
        modules_.clear();    // unload all modules
64✔
559
    }
560

561
    ///////////////////////////////////////////////////////////////////////////
562
    /// \brief Remove the given locality from our connection cache
563
    void runtime_support::remove_from_connection_cache(
64✔
564
        naming::gid_type const& gid, parcelset::endpoints_type const& eps)
64✔
565
    {
566
        runtime_distributed* rt = get_runtime_distributed_ptr();
567
        if (rt == nullptr)
568
            return;
×
569

570
#if defined(HPX_HAVE_NETWORKING)
571
        // instruct our connection cache to drop all connections it is holding
×
572
        rt->get_parcel_handler().remove_from_connection_cache(gid, eps);
×
573
#else
574
        HPX_UNUSED(gid);
575
        HPX_UNUSED(eps);
576
#endif
577
    }
×
578

579
    ///////////////////////////////////////////////////////////////////////////
580
    void runtime_support::run()
581
    {
582
        std::unique_lock<std::mutex> l(mtx_);
583
        stop_called_ = false;
584
        stop_done_ = false;
585
        terminated_ = false;
32✔
586
        shutdown_all_invoked_.store(false);
587
    }
32✔
588

32✔
589
    void runtime_support::wait()
32✔
590
    {
32✔
591
        std::unique_lock<std::mutex> l(mtx_);
592
        while (!stop_done_)
32✔
593
        {
594
            LRT_(info).format("runtime_support: about to enter wait state");
32✔
595
            wait_condition_.wait(l);    //-V1089
596
            LRT_(info).format("runtime_support: exiting wait state");
32✔
597
        }
64✔
598
    }
599

32✔
600
    void runtime_support::stop(double timeout, hpx::id_type const& respond_to,
32✔
601
        bool remove_from_remote_caches)
32✔
602
    {
603
        std::unique_lock<std::mutex> l(mtx_);
32✔
604
        if (!stop_called_)
605
        {
32✔
606
            // push pending logs
607
            components::cleanup_logging();
608

32✔
609
            HPX_ASSERT(!terminated_);
32✔
610

611
            applier::applier& appl = hpx::applier::get_applier();
612
            threads::threadmanager& tm = appl.get_thread_manager();
32✔
613
            agas::addressing_service& agas_client = naming::get_agas_client();
614

615
            error_code ec(throwmode::lightweight);
616

32✔
617
            stop_called_ = true;
32✔
618

32✔
619
            {
620
                unlock_guard<std::mutex> ul(mtx_);
621

622
                util::runtime_configuration& cfg = get_runtime().get_config();
32✔
623
                std::size_t const shutdown_check_count =
624
                    util::get_entry_as<std::size_t>(
625
                        cfg, "hpx.shutdown_check_count", 10);
626
                bool const success = util::detail::yield_while_count_timeout(
627
                    [&tm] {
32✔
628
                        tm.cleanup_terminated(true);
629
                        return tm.is_busy();
32✔
630
                    },
64✔
631
                    shutdown_check_count,
64✔
632
                    std::chrono::duration<double>(timeout),
32✔
633
                    "runtime_support::stop");
×
634

×
635
                // If it took longer than expected, kill all suspended threads as
636
                // well.
637
                if (!success)
638
                {
639
                    // now we have to wait for all threads to be aborted
640
                    util::detail::yield_while_count_timeout(
641
                        [&tm] {
642
                            tm.abort_all_suspended_threads();
32✔
643
                            tm.cleanup_terminated(true);
644
                            return tm.is_busy();
645
                        },
64✔
646
                        shutdown_check_count,
32✔
647
                        std::chrono::duration<double>(timeout),
×
648
                        "runtime_support::stop");
×
649
                }
×
650

651
                // Drop the locality from the partition table.
652
                naming::gid_type const here = agas_client.get_local_locality();
653

654
                // unregister fixed components
655
                agas_client.unbind_local(
656
                    appl.get_runtime_support_raw_gid(), ec);
657

658
                if (remove_from_remote_caches)
659
                    remove_here_from_connection_cache();
660

661
                agas_client.unregister_locality(here, ec);
662

663
                if (remove_from_remote_caches)
32✔
664
                    remove_here_from_console_connection_cache();
×
665

666
                if (respond_to)
32✔
667
                {
668
#if !defined(HPX_COMPUTE_DEVICE_CODE)
32✔
669
#if defined(HPX_HAVE_NETWORKING)
×
670
                    // respond synchronously
671
                    using void_lco_type = lcos::base_lco_with_value<void>;
672
                    using action_type = void_lco_type::set_event_action;
673
#endif
674
#else
675
                    HPX_ASSERT(false);
676
#endif
677

678
                    naming::address addr;
679
                    if (agas::is_local_address_cached(respond_to, addr))
680
                    {
681
                        // this should never happen
682
                        HPX_ASSERT(false);
683
                    }
3✔
684
#if defined(HPX_HAVE_NETWORKING)
3✔
685
                    else
686
                    {
687
#if !defined(HPX_COMPUTE_DEVICE_CODE)
688
                        // apply remotely, parcel is sent synchronously
689
                        hpx::detail::post_r_sync<action_type>(
690
                            HPX_MOVE(addr), respond_to);
691
#else
692
                        HPX_ASSERT(false);
693
#endif
694
                    }
695
#endif
696
                }
697
            }
698

699
            stop_done_ = true;
700
            wait_condition_.notify_all();
701

702
            // The main thread notifies stop_condition_, so don't wait if we're
703
            // on the main thread.
704
            if (std::this_thread::get_id() != main_thread_id_)
32✔
705
            {
32✔
706
                stop_condition_.wait(l);    // wait for termination //-V1089
707
            }
708
        }
709
    }
32✔
710

711
    void runtime_support::notify_waiting_main()
32✔
712
    {
713
        std::unique_lock<std::mutex> l(mtx_);
714
        if (!stop_called_)
32✔
715
        {
716
            stop_called_ = true;
×
717
            stop_done_ = true;
718
            wait_condition_.notify_all();
×
719

×
720
            // The main thread notifies stop_condition_, so don't wait if we're
721
            // on the main thread.
×
722
            if (std::this_thread::get_id() != main_thread_id_)
×
723
            {
×
724
                // wait for termination
725
                stop_condition_.wait(l);    //-V1089
726
            }
727
        }
×
728
    }
729

730
    // this will be called after the thread manager has exited
×
731
    void runtime_support::stopped()
732
    {
733
        std::lock_guard<std::mutex> l(mtx_);
×
734
        if (!terminated_)
735
        {
736
            terminated_ = true;
32✔
737
            stop_condition_.notify_all();    // finished cleanup/termination
738
        }
32✔
739
    }
32✔
740

741
#if defined(HPX_HAVE_NETWORKING)
32✔
742
    namespace detail {
32✔
743
        void handle_list_parcelports()
744
        {
32✔
745
            // make sure all output is kept together
746
            std::ostringstream strm;
747
            strm << std::string(79, '*') << '\n';
748
            strm << "locality: " << hpx::get_locality_id() << '\n';
×
749

750
            get_runtime_distributed().get_parcel_handler().list_parcelports(
751
                strm);
×
752

×
753
            std::cout << strm.str();
×
754
        }
755
    }    // namespace detail
×
756
#endif
757

758
    ///////////////////////////////////////////////////////////////////////////
×
759
    int runtime_support::load_components()
×
760
    {
761
        // load components now that AGAS is up
762
        util::runtime_configuration& ini = get_runtime().get_config();
763

764
        // first static components
32✔
765
        ini.load_components_static(components::get_static_module_data());
766

767
        // modules loaded dynamically should not register themselves statically
32✔
768
        components::get_initial_static_loading() = false;
769

770
        // make sure every component module gets asked for startup/shutdown
32✔
771
        // functions only once
772
        std::set<std::string> startup_handled;
773

32✔
774
        // collect additional command-line options
775
        hpx::program_options::options_description options;
776
        options.add(get_runtime().get_app_options());
777

778
        // then dynamic ones
779
        agas::addressing_service& client = naming::get_agas_client();
780
        int result = load_components(
32✔
781
            ini, client.get_local_locality(), client, options, startup_handled);
32✔
782
        if (result != 0)
783
        {
784
            return result;
32✔
785
        }
32✔
786

787
        if (!load_plugins(ini, options, startup_handled))
32✔
788
        {
789
            return -2;
790
        }
791

792
#if defined(HPX_HAVE_NETWORKING)
32✔
793
        return util::handle_late_commandline_options(ini, options,
794
            &hpx::detail::handle_print_bind, &detail::handle_list_parcelports);
795
#else
796
        return util::handle_late_commandline_options(
797
            ini, options, &hpx::detail::handle_print_bind);
798
#endif
32✔
799
    }
800

801
    void runtime_support::call_startup_functions(bool pre_startup)
802
    {
803
        if (pre_startup)
804
        {
32✔
805
            get_runtime().set_state(hpx::state::pre_startup);
806
            for (startup_function_type& f : pre_startup_functions_)
64✔
807
            {
808
                f();
64✔
809
            }
810
        }
32✔
811
        else
143✔
812
        {
813
            get_runtime().set_state(hpx::state::startup);
814
            for (startup_function_type& f : startup_functions_)
815
            {
816
                f();
817
            }
818
        }
32✔
819
    }
65✔
820

821
    void runtime_support::call_shutdown_functions(bool pre_shutdown)
822
    {
823
        runtime& rt = get_runtime();
824
        if (pre_shutdown)
64✔
825
        {
826
            rt.set_state(hpx::state::pre_shutdown);
64✔
827
            for (shutdown_function_type& f : pre_shutdown_functions_)
828
            {
64✔
829
                try
64✔
830
                {
831
                    f();
32✔
832
                }
70✔
833
                catch (...)
834
                {
835
                    rt.report_error(std::current_exception());
836
                }
837
            }
838
        }
×
839
        else
840
        {
×
841
            rt.set_state(hpx::state::shutdown);
×
842
            for (shutdown_function_type& f : shutdown_functions_)
843
            {
844
                try
845
                {
846
                    f();
32✔
847
                }
4,109✔
848
                catch (...)
849
                {
850
                    rt.report_error(std::current_exception());
851
                }
852
            }
853
        }
×
854
    }
855

×
856
    // working around non-copy-ability of packaged_task
×
857
    struct indirect_packaged_task
858
    {
859
        typedef hpx::packaged_task<void()> packaged_task_type;
64✔
860

861
        indirect_packaged_task()
862
          : pt(std::make_shared<packaged_task_type>([]() {}))
×
863
        {
864
        }
865

866
        hpx::future<void> get_future()
867
        {
×
868
            return pt->get_future();
869
        }
870

871
        template <typename... Ts>
872
        void operator()(Ts&&... /* vs */)
873
        {
×
874
            // This needs to be run on a HPX thread
875
            hpx::post(HPX_MOVE(*pt));
876
            pt.reset();
877
        }
×
878

879
        std::shared_ptr<packaged_task_type> pt;
880
    };
881

882
    void runtime_support::remove_here_from_connection_cache()
×
883
    {
884
#if !defined(HPX_COMPUTE_DEVICE_CODE)
885
#if defined(HPX_HAVE_NETWORKING)
886
        runtime_distributed* rtd = get_runtime_distributed_ptr();
887
        if (rtd == nullptr)
×
888
            return;
889

890
        std::vector<hpx::id_type> locality_ids = find_remote_localities();
891

×
892
        typedef server::runtime_support::remove_from_connection_cache_action
×
893
            action_type;
×
894

895
        std::vector<future<void>> callbacks;
×
896
        callbacks.reserve(locality_ids.size());
897

898
        action_type act;
899
        for (hpx::id_type const& id : locality_ids)
900
        {
×
901
            // console is handled separately
×
902
            if (naming::get_locality_id_from_id(id) == 0)
903
                continue;
904

×
905
            indirect_packaged_task ipt;
906
            callbacks.emplace_back(ipt.get_future());
907
            hpx::post_cb(
×
908
                act, id, HPX_MOVE(ipt), agas::get_locality(), rtd->endpoints());
×
909
        }
910

911
        hpx::wait_all(callbacks);
×
912
#endif
913
#else
×
914
        HPX_ASSERT(false);
915
#endif
916
    }
917

918
    void runtime_support::remove_here_from_console_connection_cache()
919
    {
920
#if !defined(HPX_COMPUTE_DEVICE_CODE)
921
#if defined(HPX_HAVE_NETWORKING)
×
922
        runtime_distributed* rtd = get_runtime_distributed_ptr();
923
        if (rtd == nullptr)
×
924
            return;
925

926
        typedef server::runtime_support::remove_from_connection_cache_action
927
            action_type;
×
928

×
929
        action_type act;
×
930
        indirect_packaged_task ipt;
931
        future<void> callback = ipt.get_future();
932

933
        // handle console separately
934
        id_type id = naming::get_id_from_locality_id(0);
935
        hpx::post_cb(
936
            act, id, HPX_MOVE(ipt), agas::get_locality(), rtd->endpoints());
937

938
        callback.wait();
939
#endif
940
#else
941
        HPX_ASSERT(false);
×
942
#endif
943
    }
×
944

945
    ///////////////////////////////////////////////////////////////////////////
946
#if defined(HPX_HAVE_NETWORKING)
947
    void runtime_support::register_message_handler(
948
        char const* message_handler_type, char const* action, error_code& ec)
949
    {
950
        // locate the factory for the requested plugin type
951
        typedef std::unique_lock<plugin_map_mutex_type> plugin_map_scoped_lock;
952
        plugin_map_scoped_lock l(p_mtx_);
1,088✔
953

954
        plugin_map_type::const_iterator it =
955
            plugins_.find(message_handler_type);
956
        if (it == plugins_.end() || !(*it).second.first)
957
        {
1,088✔
958
            l.unlock();
959
            if (ec.category() != hpx::get_lightweight_hpx_category())
960
            {
2,176✔
961
                // we don't know anything about this component
1,088✔
962
                HPX_THROWS_IF(ec, hpx::error::bad_plugin_type,
963
                    "runtime_support::create_message_handler",
×
964
                    "attempt to create message handler plugin instance of "
×
965
                    "invalid/unknown type: {}",
966
                    message_handler_type);
967
            }
×
968
            else
969
            {
970
                // lightweight error handling
971
                HPX_THROWS_IF(ec, hpx::error::bad_plugin_type,
972
                    "runtime_support::create_message_handler",
973
                    "attempt to create message handler plugin instance of "
974
                    "invalid/unknown type");
975
            }
976
            return;
×
977
        }
978

979
        l.unlock();
980

981
        // create new component instance
×
982
        std::shared_ptr<plugins::message_handler_factory_base> factory(
983
            std::static_pointer_cast<plugins::message_handler_factory_base>(
984
                (*it).second.first));
1,088✔
985

986
        factory->register_action(action, ec);
987

988
        if (ec)
989
        {
1,088✔
990
            HPX_THROWS_IF(ec, hpx::error::bad_plugin_type,
991
                "runtime_support::register_message_handler",
1,088✔
992
                "couldn't register action '{}' for message handler plugin of "
993
                "type: {}",
1,088✔
994
                action, message_handler_type);
995
            return;
×
996
        }
997

998
        if (&ec != &throws)
999
            ec = make_success_code();
1000

1001
        // log result if requested
1002
        LRT_(info).format(
1003
            "successfully registered message handler plugin of type: {}",
1,088✔
1004
            message_handler_type);
2,176✔
1005
    }
1006

1007
    parcelset::policies::message_handler*
1,088✔
1008
    runtime_support::create_message_handler(char const* message_handler_type,
1009
        char const* action, parcelset::parcelport* pp, std::size_t num_messages,
1010
        std::size_t interval, error_code& ec)
1011
    {
1012
        // locate the factory for the requested plugin type
1013
        typedef std::unique_lock<plugin_map_mutex_type> plugin_map_scoped_lock;
6✔
1014
        plugin_map_scoped_lock l(p_mtx_);
1015

1016
        plugin_map_type::const_iterator it =
1017
            plugins_.find(message_handler_type);
1018
        if (it == plugins_.end() || !(*it).second.first)
1019
        {
6✔
1020
            l.unlock();
1021
            if (ec.category() != hpx::get_lightweight_hpx_category())
1022
            {
12✔
1023
                // we don't know anything about this component
6✔
1024
                HPX_THROWS_IF(ec, hpx::error::bad_plugin_type,
1025
                    "runtime_support::create_message_handler",
×
1026
                    "attempt to create message handler plugin instance of "
×
1027
                    "invalid/unknown type: {}",
1028
                    message_handler_type);
1029
            }
×
1030
            else
1031
            {
1032
                // lightweight error handling
1033
                HPX_THROWS_IF(ec, hpx::error::bad_plugin_type,
1034
                    "runtime_support::create_message_handler",
1035
                    "attempt to create message handler plugin instance of "
1036
                    "invalid/unknown type");
1037
            }
1038
            return nullptr;
×
1039
        }
1040

1041
        l.unlock();
1042

1043
        // create new component instance
×
1044
        std::shared_ptr<plugins::message_handler_factory_base> factory(
1045
            std::static_pointer_cast<plugins::message_handler_factory_base>(
1046
                (*it).second.first));
6✔
1047

1048
        parcelset::policies::message_handler* mh =
1049
            factory->create(action, pp, num_messages, interval);
1050
        if (nullptr == mh)
1051
        {
6✔
1052
            HPX_THROWS_IF(ec, hpx::error::bad_plugin_type,
1053
                "runtime_support::create_message_handler",
1054
                "couldn't create message handler plugin of type: {}",
6✔
1055
                message_handler_type);
6✔
1056
            return nullptr;
1057
        }
×
1058

1059
        if (&ec != &throws)
1060
            ec = make_success_code();
1061

×
1062
        // log result if requested
1063
        LRT_(info).format(
1064
            "successfully created message handler plugin of type: {}",
6✔
1065
            message_handler_type);
12✔
1066
        return mh;
1067
    }
1068

6✔
1069
    serialization::binary_filter* runtime_support::create_binary_filter(
1070
        char const* binary_filter_type, bool compress,
1071
        serialization::binary_filter* next_filter, error_code& ec)
1072
    {
1073
        // locate the factory for the requested plugin type
1074
        typedef std::unique_lock<plugin_map_mutex_type> plugin_map_scoped_lock;
×
1075
        plugin_map_scoped_lock l(p_mtx_);
1076

1077
        plugin_map_type::const_iterator it = plugins_.find(binary_filter_type);
1078
        if (it == plugins_.end() || !(*it).second.first)
1079
        {
1080
            l.unlock();
×
1081
            // we don't know anything about this component
1082
            HPX_THROWS_IF(ec, hpx::error::bad_plugin_type,
×
1083
                "runtime_support::create_binary_filter",
×
1084
                "attempt to create binary filter plugin instance of "
1085
                "invalid/unknown type: {}",
×
1086
                binary_filter_type);
1087
            return nullptr;
×
1088
        }
1089

1090
        l.unlock();
1091

1092
        // create new component instance
×
1093
        std::shared_ptr<plugins::binary_filter_factory_base> factory(
1094
            std::static_pointer_cast<plugins::binary_filter_factory_base>(
1095
                (*it).second.first));
×
1096

1097
        serialization::binary_filter* bf =
1098
            factory->create(compress, next_filter);
1099
        if (nullptr == bf)
1100
        {
×
1101
            HPX_THROWS_IF(ec, hpx::error::bad_plugin_type,
1102
                "runtime_support::create_binary_filter",
1103
                "couldn't create binary filter plugin of type: {}",
×
1104
                binary_filter_type);
×
1105
            return nullptr;
1106
        }
×
1107

1108
        if (&ec != &throws)
1109
            ec = make_success_code();
1110

×
1111
        // log result if requested
1112
        LRT_(info).format(
1113
            "successfully created binary filter handler plugin of type: {}",
×
1114
            binary_filter_type);
×
1115
        return bf;
1116
    }
1117
#endif
×
1118

1119
    ///////////////////////////////////////////////////////////////////////////
1120
    bool runtime_support::load_component_static(util::section& ini,
1121
        std::string const& instance, std::string const& component,
1122
        filesystem::path const& lib, naming::gid_type const& /* prefix */,
1123
        agas::addressing_service& /* agas_client */, bool /* isdefault */,
1124
        bool /* isenabled */,
1125
        hpx::program_options::options_description& options,
859✔
1126
        std::set<std::string>& startup_handled)
1127
    {
1128
        try
1129
        {
1130
            // initialize the factory instance using the preferences from the
1131
            // ini files
1132
            util::section const* component_ini = nullptr;
1133
            std::string component_section("hpx.components." + instance);
1134
            if (ini.has_section(component_section))
1135
                component_ini = ini.get_section(component_section);
1136

1137
            if (nullptr == component_ini ||
1138
                "0" == component_ini->get_entry("no_factory", "0"))
859✔
1139
            {
859✔
1140
                util::plugin::get_plugins_list_type f;
859✔
1141
                if (!components::get_static_factory(instance, f))
1142
                {
1,718✔
1143
                    LRT_(warning).format(
3,436✔
1144
                        "static loading failed: {}: {}: couldn't find factory "
1145
                        "in global static factory map",
1146
                        lib.string(), instance);
859✔
1147
                    return false;
1148
                }
×
1149

1150
                LRT_(info).format(
1151
                    "static loading succeeded: {}: {}", lib.string(), instance);
×
1152
            }
×
1153

1154
            // make sure startup/shutdown registration is called once for each
1155
            // module, same for plugins
859✔
1156
            if (startup_handled.find(component) == startup_handled.end())
×
1157
            {
1158
                error_code ec(throwmode::lightweight);
1159
                startup_handled.insert(component);
1160
                load_commandline_options_static(component, options, ec);
1161
                if (ec)
859✔
1162
                    ec = error_code(throwmode::lightweight);
1163
                load_startup_shutdown_functions_static(component, ec);
1164
            }
1165
        }
48✔
1166
        catch (hpx::exception const&)
48✔
1167
        {
×
1168
            throw;
48✔
1169
        }
1170
        catch (std::logic_error const& e)
1171
        {
×
1172
            LRT_(warning).format("static loading failed: {}: {}: {}",
1173
                lib.string(), instance, e.what());
×
1174
            return false;
×
1175
        }
×
1176
        catch (std::exception const& e)
1177
        {
×
1178
            LRT_(warning).format("static loading failed: {}: {}: {}",
×
1179
                lib.string(), instance, e.what());
1180
            return false;
×
1181
        }
×
1182
        return true;    // component got loaded
1183
    }
×
1184

×
1185
    ///////////////////////////////////////////////////////////////////////////
1186
    // Load all components from the ini files found in the configuration
×
1187
    int runtime_support::load_components(util::section& ini,
859✔
1188
        naming::gid_type const& prefix, agas::addressing_service& agas_client,
1189
        hpx::program_options::options_description& options,
1190
        std::set<std::string>& startup_handled)
1191
    {
1192
        // load all components as described in the configuration information
32✔
1193
        if (!ini.has_section("hpx.components"))
1194
        {
1195
            LRT_(info).format(
1196
                "No components found/loaded, HPX will be mostly non-functional "
1197
                "(no section [hpx.components] found).");
1198
            return 0;    // no components to load
64✔
1199
        }
1200

×
1201
        // each shared library containing components may have an ini section
1202
        //
1203
        // # mandatory section describing the component module
×
1204
        // [hpx.components.instance_name]
1205
        //  name = ...           # the name of this component module
1206
        //  path = ...           # the path where to find this component module
1207
        //  enabled = false      # optional (default is assumed to be true)
1208
        //  static = false       # optional (default is assumed to be false)
1209
        //
1210
        // # optional section defining additional properties for this module
1211
        // [hpx.components.instance_name.settings]
1212
        //  key = value
1213
        //
1214
        util::section* sec = ini.get_section("hpx.components");
1215
        if (nullptr == sec)
1216
        {
1217
            LRT_(error).format("nullptr section found");
1218
            return 0;    // something bad happened
1219
        }
32✔
1220

32✔
1221
        util::section::section_map const& s = (*sec).get_sections();
1222
        typedef util::section::section_map::const_iterator iterator;
×
1223
        iterator end = s.end();
×
1224
        for (iterator i = s.begin(); i != end; ++i)
1225
        {
1226
            namespace fs = filesystem;
1227

1228
            // the section name is the instance name of the component
1229
            util::section const& sect = i->second;
1,019✔
1230
            std::string instance(sect.get_name());
1231
            std::string component;
1232

1233
            if (sect.has_entry("name"))
1234
                component = sect.get_entry("name");
987✔
1235
            else
1236
                component = instance;
1237

1238
            bool isenabled = true;
1,974✔
1239
            if (sect.has_entry("enabled"))
1,974✔
1240
            {
1241
                std::string tmp = sect.get_entry("enabled");
1242
                hpx::string_util::to_lower(tmp);
1243
                if (tmp == "no" || tmp == "false" || tmp == "0")
1244
                {
1,974✔
1245
                    LRT_(info).format(
1246
                        "component factory disabled: {}", instance);
987✔
1247
                    isenabled = false;    // this component has been disabled
987✔
1248
                }
987✔
1249
            }
1250

×
1251
            // test whether this component section was generated
1252
            bool isdefault = false;
1253
            if (sect.has_entry("isdefault"))
1254
            {
1255
                std::string tmp = sect.get_entry("isdefault");
1256
                hpx::string_util::to_lower(tmp);
1257
                if (tmp == "true")
1258
                    isdefault = true;
1,974✔
1259
            }
1260

×
1261
            fs::path lib;
×
1262
            try
×
1263
            {
1264
                std::string component_path;
1265
                if (sect.has_entry("path"))
1266
                    component_path = sect.get_entry("path");
1267
                else
1268
                    component_path = HPX_DEFAULT_COMPONENT_PATH;
1269

1270
                hpx::string_util::char_separator sep(HPX_INI_PATH_DELIMITER);
1,974✔
1271
                hpx::string_util::tokenizer tokens(component_path, sep);
512✔
1272
                std::error_code fsec;
1273
                for (auto it = tokens.begin(); it != tokens.end(); ++it)
1,462✔
1274
                {
1275
                    lib = fs::path(*it);
987✔
1276
                    fs::path lib_path =
1277
                        lib / std::string(HPX_MAKE_DLL_STRING(component));
1278
                    if (fs::exists(lib_path, fsec))
1,147✔
1279
                    {
1280
                        break;
256✔
1281
                    }
1282
                    lib.clear();
512✔
1283
                }
256✔
1284

1285
                if (sect.get_entry("static", "0") == "1")
1286
                {
1287
                    load_component_static(ini, instance, component, lib, prefix,
1288
                        agas_client, isdefault, isenabled, options,
1,243✔
1289
                        startup_handled);
1290
                }
1,974✔
1291
                else
1292
                {
859✔
1293
#if defined(HPX_HAVE_STATIC_LINKING)
1294
                    HPX_THROW_EXCEPTION(hpx::error::service_unavailable,
1295
                        "runtime_support::load_components",
1296
                        "static linking configuration does not support dynamic "
1297
                        "loading of component '{}'",
1298
                        instance);
1299
#else
1300
                    load_component_dynamic(ini, instance, component, lib,
1301
                        prefix, agas_client, isdefault, isenabled, options,
1302
                        startup_handled);
1303
#endif
1304
                }
1305
            }
128✔
1306
            catch (hpx::exception const& e)
1307
            {
1308
                LRT_(warning).format(
1309
                    "caught exception while loading {}, {}: {}", instance,
1310
                    e.get_error_code().get_message(), e.what());
1311
                if (e.get_error_code().value() ==
×
1312
                    hpx::error::commandline_option_error)
1313
                {
×
1314
                    std::cerr << "runtime_support::load_components: "
1315
                              << "invalid command line option(s) to "
×
1316
                              << instance << " component: " << e.what()
×
1317
                              << std::endl;
1318
                }
1319
            }
1320
        }    // for
1321

×
1322
        return 0;
1323
    }
1324

×
1325
    ///////////////////////////////////////////////////////////////////////////
987✔
1326
    bool runtime_support::load_startup_shutdown_functions_static(
1327
        std::string const& mod, error_code& ec)
1328
    {
1329
        try
1330
        {
1331
            // get the factory, may fail
48✔
1332
            util::plugin::get_plugins_list_type f;
1333
            if (!components::get_static_startup_shutdown(mod, f))
1334
            {
1335
                LRT_(debug).format(
1336
                    "static loading of startup/shutdown functions failed: {}: "
1337
                    "couldn't find module in global static startup/shutdown "
1338
                    "functions data map",
48✔
1339
                    mod);
1340
                return false;
33✔
1341
            }
1342

1343
            util::plugin::static_plugin_factory<component_startup_shutdown_base>
1344
                pf(f);
1345

33✔
1346
            // create the startup_shutdown object
1347
            std::shared_ptr<component_startup_shutdown_base> startup_shutdown(
1348
                pf.create("startup_shutdown", ec));
1349
            if (ec)
1350
            {
1351
                LRT_(debug).format("static loading of startup/shutdown "
1352
                                   "functions failed: {}: {}",
1353
                    mod, get_error_what(ec));
30✔
1354
                return false;
15✔
1355
            }
1356

×
1357
            startup_function_type startup;
1358
            bool pre_startup = true;
×
1359
            if (startup_shutdown->get_startup_function(startup, pre_startup))
1360
            {
1361
                if (!startup.empty())
1362
                {
15✔
1363
                    if (pre_startup)
15✔
1364
                    {
15✔
1365
                        pre_startup_functions_.push_back(HPX_MOVE(startup));
1366
                    }
15✔
1367
                    else
1368
                    {
15✔
1369
                        startup_functions_.push_back(HPX_MOVE(startup));
1370
                    }
15✔
1371
                }
1372
            }
1373

1374
            shutdown_function_type shutdown;
×
1375
            bool pre_shutdown = false;
1376
            if (startup_shutdown->get_shutdown_function(shutdown, pre_shutdown))
1377
            {
1378
                if (!shutdown.empty())
1379
                {
15✔
1380
                    if (pre_shutdown)
15✔
1381
                    {
15✔
1382
                        pre_shutdown_functions_.push_back(HPX_MOVE(shutdown));
1383
                    }
15✔
1384
                    else
1385
                    {
15✔
1386
                        shutdown_functions_.push_back(HPX_MOVE(shutdown));
1387
                    }
×
1388
                }
1389
            }
1390
        }
1391
        catch (hpx::exception const&)
15✔
1392
        {
1393
            throw;
1394
        }
1395
        catch (std::logic_error const& e)
1396
        {
×
1397
            LRT_(debug).format(
1398
                "static loading of startup/shutdown functions failed: {}: {}",
×
1399
                mod, e.what());
×
1400
            return false;
×
1401
        }
1402
        catch (std::exception const& e)
×
1403
        {
1404
            LRT_(debug).format(
×
1405
                "static loading of startup/shutdown functions failed: {}: {}",
1406
                mod, e.what());
×
1407
            return false;
×
1408
        }
1409
        return true;    // startup/shutdown functions got registered
×
1410
    }
1411

×
1412
    ///////////////////////////////////////////////////////////////////////////
1413
    bool runtime_support::load_commandline_options_static(
×
1414
        std::string const& mod,
15✔
1415
        hpx::program_options::options_description& options, error_code& ec)
1416
    {
1417
        try
1418
        {
48✔
1419
            util::plugin::get_plugins_list_type f;
1420
            if (!components::get_static_commandline(mod, f))
1421
            {
1422
                LRT_(debug).format("static loading of command-line options "
1423
                                   "failed: {}: couldn't find module in global "
1424
                                   "static command line data map",
1425
                    mod);
48✔
1426
                return false;
1427
            }
48✔
1428

1429
            // get the factory, may fail
1430
            hpx::util::plugin::static_plugin_factory<component_commandline_base>
1431
                pf(f);
48✔
1432

1433
            // create the startup_shutdown object
1434
            std::shared_ptr<component_commandline_base> commandline_options(
1435
                pf.create("commandline_options", ec));
1436
            if (ec)
1437
            {
1438
                LRT_(debug).format(
1439
                    "static loading of command-line options failed: {}: {}",
1440
                    mod, get_error_what(ec));
×
1441
                return false;
×
1442
            }
1443

×
1444
            options.add(commandline_options->add_commandline_options());
1445
        }
×
1446
        catch (hpx::exception const&)
1447
        {
1448
            throw;
1449
        }
×
1450
        catch (std::logic_error const& e)
1451
        {
×
1452
            LRT_(debug).format(
1453
                "static loading of command-line options failed: {}: {}", mod,
×
1454
                e.what());
×
1455
            return false;
×
1456
        }
1457
        catch (std::exception const& e)
×
1458
        {
1459
            LRT_(debug).format(
×
1460
                "static loading of command-line options failed: {}: {}", mod,
1461
                e.what());
×
1462
            return false;
×
1463
        }
1464
        return true;    // startup/shutdown functions got registered
×
1465
    }
1466

×
1467
#if !defined(HPX_HAVE_STATIC_LINKING)
1468
    bool runtime_support::load_component_dynamic(util::section& ini,
×
1469
        std::string const& instance, std::string const& component,
×
1470
        filesystem::path lib, naming::gid_type const& prefix,
1471
        agas::addressing_service& agas_client, bool isdefault, bool isenabled,
1472
        hpx::program_options::options_description& options,
1473
        std::set<std::string>& startup_handled)
128✔
1474
    {
1475
        modules_map_type::iterator it =
1476
            modules_.find(HPX_MANGLE_STRING(component));
1477
        if (it != modules_.cend())
1478
        {
1479
            // use loaded module, instantiate the requested factory
1480
            return load_component((*it).second, ini, instance, component, lib,
1481
                prefix, agas_client, isdefault, isenabled, options,
128✔
1482
                startup_handled);
128✔
1483
        }
1484

1485
        // first, try using the path as the full path to the library
96✔
1486
        error_code ec(throwmode::lightweight);
1487
        hpx::util::plugin::dll d(lib.string(), HPX_MANGLE_STRING(component));
1488
        d.load_library(ec);
1489
        if (ec)
1490
        {
1491
            // build path to component to load
1492
            std::string libname(HPX_MAKE_DLL_STRING(component));
64✔
1493
            lib /= filesystem::path(libname);
1494
            d.load_library(ec);
32✔
1495
            if (ec)
1496
            {
1497
                LRT_(warning).format("dynamic loading failed: {}: {}: {}",
×
1498
                    lib.string(), instance, get_error_what(ec));
×
1499
                return false;    // next please :-P
1500
            }
×
1501
        }
1502

×
1503
        // now, instantiate the requested factory
×
1504
        if (!load_component(d, ini, instance, component, lib, prefix,
1505
                agas_client, isdefault, isenabled, options, startup_handled))
1506
        {
1507
            return false;    // next please :-P
1508
        }
1509

32✔
1510
        modules_.emplace(HPX_MANGLE_STRING(component), d);
1511
        return true;
1512
    }
1513

1514
    bool runtime_support::load_startup_shutdown_functions(
1515
        hpx::util::plugin::dll& d, error_code& ec)
32✔
1516
    {
1517
        try
32✔
1518
        {
1519
            // get the factory, may fail
160✔
1520
            hpx::util::plugin::plugin_factory<component_startup_shutdown_base>
1521
                pf(d, "startup_shutdown");
1522

1523
            // create the startup_shutdown object
1524
            std::shared_ptr<component_startup_shutdown_base> startup_shutdown(
1525
                pf.create("startup_shutdown", ec));
1526
            if (ec)
160✔
1527
            {
1528
                LRT_(debug).format(
1529
                    "loading of startup/shutdown functions failed: {}: {}",
1530
                    d.get_name(), get_error_what(ec));
320✔
1531
                return false;
160✔
1532
            }
1533

32✔
1534
            startup_function_type startup;
1535
            bool pre_startup = true;
×
1536
            if (startup_shutdown->get_startup_function(startup, pre_startup))
1537
            {
1538
                if (pre_startup)
1539
                    pre_startup_functions_.push_back(HPX_MOVE(startup));
128✔
1540
                else
128✔
1541
                    startup_functions_.push_back(HPX_MOVE(startup));
128✔
1542
            }
1543

96✔
1544
            shutdown_function_type shutdown;
96✔
1545
            bool pre_shutdown = false;
1546
            if (startup_shutdown->get_shutdown_function(shutdown, pre_shutdown))
×
1547
            {
1548
                if (pre_shutdown)
1549
                    pre_shutdown_functions_.push_back(HPX_MOVE(shutdown));
128✔
1550
                else
128✔
1551
                    shutdown_functions_.push_back(HPX_MOVE(shutdown));
128✔
1552
            }
1553
        }
×
1554
        catch (hpx::exception const&)
×
1555
        {
1556
            throw;
×
1557
        }
1558
        catch (std::logic_error const& e)
1559
        {
×
1560
            LRT_(debug).format(
1561
                "loading of startup/shutdown functions failed: {}: {}",
×
1562
                d.get_name(), e.what());
×
1563
            return false;
×
1564
        }
1565
        catch (std::exception const& e)
×
1566
        {
1567
            LRT_(debug).format(
×
1568
                "loading of startup/shutdown functions failed: {}: {}",
1569
                d.get_name(), e.what());
×
1570
            return false;
×
1571
        }
1572
        return true;    // startup/shutdown functions got registered
×
1573
    }
1574

×
1575
    bool runtime_support::load_commandline_options(hpx::util::plugin::dll& d,
1576
        hpx::program_options::options_description& options, error_code& ec)
×
1577
    {
128✔
1578
        try
1579
        {
1580
            // get the factory, may fail
160✔
1581
            hpx::util::plugin::plugin_factory<component_commandline_base> pf(
1582
                d, "commandline_options");
1583

1584
            // create the startup_shutdown object
1585
            std::shared_ptr<component_commandline_base> commandline_options(
1586
                pf.create("commandline_options", ec));
1587
            if (ec)
160✔
1588
            {
1589
                LRT_(debug).format(
1590
                    "loading of command-line options failed: {}: {}",
1591
                    d.get_name(), get_error_what(ec));
320✔
1592
                return false;
160✔
1593
            }
1594

128✔
1595
            options.add(commandline_options->add_commandline_options());
1596
        }
×
1597
        catch (hpx::exception const&)
1598
        {
1599
            throw;
1600
        }
32✔
1601
        catch (std::logic_error const& e)
1602
        {
×
1603
            LRT_(debug).format("loading of command-line options failed: {}: {}",
1604
                d.get_name(), e.what());
×
1605
            return false;
×
1606
        }
×
1607
        catch (std::exception const& e)
1608
        {
×
1609
            LRT_(debug).format("loading of command-line options failed: {}: {}",
×
1610
                d.get_name(), e.what());
1611
            return false;
×
1612
        }
×
1613
        return true;    // startup/shutdown functions got registered
1614
    }
×
1615

×
1616
    ///////////////////////////////////////////////////////////////////////////
1617
    bool runtime_support::load_component(hpx::util::plugin::dll& d,
×
1618
        util::section& ini, std::string const& instance,
32✔
1619
        std::string const& /* component */, filesystem::path const& lib,
1620
        naming::gid_type const& /* prefix */,
1621
        agas::addressing_service& /* agas_client */, bool /* isdefault */,
1622
        bool /* isenabled */,
128✔
1623
        hpx::program_options::options_description& options,
1624
        std::set<std::string>& startup_handled)
1625
    {
1626
#if defined(HPX_COMPUTE_DEVICE_CODE)
1627
        HPX_UNUSED(d);
1628
        HPX_UNUSED(ini);
1629
        HPX_UNUSED(instance);
1630
        HPX_UNUSED(lib);
1631
        HPX_UNUSED(options);
1632
        HPX_UNUSED(startup_handled);
1633

1634
        return false;
1635
#else
1636
        try
1637
        {
1638
            // initialize the factory instance using the preferences from the
1639
            // ini files
1640
            util::section const* component_ini = nullptr;
1641
            std::string component_section("hpx.components." + instance);
1642
            if (ini.has_section(component_section))
1643
                component_ini = ini.get_section(component_section);
1644

1645
            if (nullptr == component_ini ||
1646
                "0" == component_ini->get_entry("no_factory", "0"))
128✔
1647
            {
128✔
1648
                // get the factory
128✔
1649
                hpx::util::plugin::plugin_factory<component_factory_base> pf(
1650
                    d, "factory");
256✔
1651

512✔
1652
                LRT_(info).format("dynamic loading succeeded: {}: {}",
1653
                    lib.string(), instance);
1654
            }
1655

64✔
1656
            // make sure startup/shutdown registration is called once for each
1657
            // module, same for plugins
64✔
1658
            if (startup_handled.find(d.get_name()) == startup_handled.end())
×
1659
            {
1660
                error_code ec(throwmode::lightweight);
1661
                startup_handled.insert(d.get_name());
1662
                load_commandline_options(d, options, ec);
1663
                if (ec)
128✔
1664
                    ec = error_code(throwmode::lightweight);
1665
                load_startup_shutdown_functions(d, ec);
1666
            }
1667
        }
128✔
1668
        catch (hpx::exception const&)
128✔
1669
        {
192✔
1670
            throw;
128✔
1671
        }
1672
        catch (std::logic_error const& e)
1673
        {
×
1674
            LRT_(warning).format("dynamic loading failed: {}: {}: {}",
1675
                lib.string(), instance, e.what());
×
1676
            return false;
×
1677
        }
×
1678
        catch (std::exception const& e)
1679
        {
×
1680
            LRT_(warning).format("dynamic loading failed: {}: {}: {}",
×
1681
                lib.string(), instance, e.what());
1682
            return false;
×
1683
        }
×
1684
        return true;    // component got loaded
1685
#endif
×
1686
    }
×
1687
#endif
1688

×
1689
    ///////////////////////////////////////////////////////////////////////////
128✔
1690
    // Load all components from the ini files found in the configuration
1691
    bool runtime_support::load_plugins(util::section& ini,
1692
        [[maybe_unused]] hpx::program_options::options_description& options,
1693
        [[maybe_unused]] std::set<std::string>& startup_handled)
1694
    {
1695
        // load all components as described in the configuration information
1696
        if (!ini.has_section("hpx.plugins"))
32✔
1697
        {
1698
            LRT_(info).format("No plugins found/loaded.");
1699
            return true;    // no plugins to load
1700
        }
1701

64✔
1702
        // each shared library containing components may have an ini section
1703
        //
×
1704
        // # mandatory section describing the component module
×
1705
        // [hpx.plugins.instance_name]
1706
        //  name = ...           # the name of this component module
1707
        //  path = ...           # the path where to find this component module
1708
        //  enabled = false      # optional (default is assumed to be true)
1709
        //  static = false       # optional (default is assumed to be false)
1710
        //
1711
        // # optional section defining additional properties for this module
1712
        // [hpx.plugins.instance_name.settings]
1713
        //  key = value
1714
        //
1715
        util::section* sec = ini.get_section("hpx.plugins");
1716
        if (nullptr == sec)
1717
        {
1718
            LRT_(error).format("nullptr section found");
1719
            return false;    // something bad happened
1720
        }
32✔
1721

32✔
1722
        util::section::section_map const& s = (*sec).get_sections();
1723
        typedef util::section::section_map::const_iterator iterator;
×
1724
        iterator end = s.end();
×
1725
        for (iterator i = s.begin(); i != end; ++i)
1726
        {
1727
            namespace fs = filesystem;
1728

1729
            // the section name is the instance name of the component
1730
            util::section const& sect = i->second;
64✔
1731
            std::string instance(sect.get_name());
1732
            std::string component;
1733

1734
            if (i->second.has_entry("name"))
1735
                component = sect.get_entry("name");
32✔
1736
            else
1737
                component = instance;
1738

1739
            bool isenabled = true;
64✔
1740
            if (sect.has_entry("enabled"))
64✔
1741
            {
1742
                std::string tmp = sect.get_entry("enabled");
1743
                hpx::string_util::to_lower(tmp);
1744
                if (tmp == "no" || tmp == "false" || tmp == "0")
1745
                {
64✔
1746
                    LRT_(info).format("plugin factory disabled: {}", instance);
1747
                    isenabled = false;    // this component has been disabled
32✔
1748
                }
32✔
1749
            }
32✔
1750

1751
            fs::path lib;
×
1752
            try
1753
            {
1754
                std::string component_path;
1755
                if (sect.has_entry("path"))
1756
                    component_path = sect.get_entry("path");
1757
                else
1758
                    component_path = HPX_DEFAULT_COMPONENT_PATH;
1759

1760
                hpx::string_util::char_separator sep(HPX_INI_PATH_DELIMITER);
64✔
1761
                hpx::string_util::tokenizer tokens(component_path, sep);
64✔
1762
                std::error_code fsec;
1763
                for (auto it = tokens.begin(); it != tokens.end(); ++it)
×
1764
                {
1765
                    lib = fs::path(*it);
32✔
1766
                    fs::path lib_path =
1767
                        lib / std::string(HPX_MAKE_DLL_STRING(component));
1768
                    if (fs::exists(lib_path, fsec))
32✔
1769
                    {
1770
                        break;
×
1771
                    }
1772
                    lib.clear();
×
1773
                }
×
1774

1775
                if (sect.get_entry("static", "0") == "1")
1776
                {
1777
                    // FIXME: implement statically linked plugins
1778
                    HPX_THROW_EXCEPTION(hpx::error::service_unavailable,
32✔
1779
                        "runtime_support::load_plugins",
1780
                        "static linking configuration does not support static "
64✔
1781
                        "loading of plugin '{}'",
1782
                        instance);
1783
                }
×
1784
                else
1785
                {
1786
#if defined(HPX_HAVE_STATIC_LINKING)
1787
                    HPX_THROW_EXCEPTION(hpx::error::service_unavailable,
1788
                        "runtime_support::load_plugins",
1789
                        "static linking configuration does not support dynamic "
1790
                        "loading of plugin '{}'",
1791
                        instance);
1792
#else
1793
                    // first, try using the path as the full path to the library
1794
                    load_plugin_dynamic(ini, instance, component, lib,
1795
                        isenabled, options, startup_handled);
1796
#endif
1797
                }
1798
            }
1799
            catch (hpx::exception const& e)
32✔
1800
            {
1801
                LRT_(warning).format(
1802
                    "caught exception while loading {}, {}: {}", instance,
1803
                    e.get_error_code().get_message(), e.what());
1804
                if (e.get_error_code().value() ==
×
1805
                    hpx::error::commandline_option_error)
1806
                {
×
1807
                    std::cerr << "runtime_support::load_plugins: "
1808
                              << "invalid command line option(s) to "
×
1809
                              << instance << " component: " << e.what()
×
1810
                              << std::endl;
1811
                }
1812
            }
1813
        }    // for
1814
        return true;
×
1815
    }
1816

1817
#if !defined(HPX_HAVE_STATIC_LINKING)
×
1818
    bool runtime_support::load_plugin(hpx::util::plugin::dll& d,
32✔
1819
        util::section& ini, std::string const& instance,
1820
        std::string const& /* plugin */, filesystem::path const& lib,
1821
        bool isenabled, hpx::program_options::options_description& options,
1822
        std::set<std::string>& startup_handled)
1823
    {
32✔
1824
        try
1825
        {
1826
            // initialize the factory instance using the preferences from the
1827
            // ini files
1828
            util::section const* glob_ini = nullptr;
1829
            if (ini.has_section("settings"))
1830
                glob_ini = ini.get_section("settings");
1831

1832
            util::section const* plugin_ini = nullptr;
1833
            std::string plugin_section("hpx.plugins." + instance);
1834
            if (ini.has_section(plugin_section))
64✔
1835
                plugin_ini = ini.get_section(plugin_section);
×
1836

1837
            error_code ec(throwmode::lightweight);
1838
            if (nullptr == plugin_ini ||
32✔
1839
                "0" == plugin_ini->get_entry("no_factory", "0"))
32✔
1840
            {
32✔
1841
                // get the factory
1842
                hpx::util::plugin::plugin_factory<plugins::plugin_factory_base>
1843
                    pf(d, "factory");
64✔
1844

128✔
1845
                // create the component factory object, if not disabled
1846
                std::shared_ptr<plugins::plugin_factory_base> const f(
1847
                    pf.create(instance, ec, glob_ini, plugin_ini, isenabled));
1848
                if (!ec)
32✔
1849
                {
1850
                    // store component factory and module for later use
1851
                    plugin_factory_type data(f, d, isenabled);
1852
                    std::pair<plugin_map_type::iterator, bool> p =
32✔
1853
                        plugins_.insert(
32✔
1854
                            plugin_map_type::value_type(instance, data));
1855

1856
                    if (!p.second)
1857
                    {
1858
                        LRT_(fatal).format(
1859
                            "duplicate plugin type: {}", instance);
64✔
1860
                        return false;
1861
                    }
32✔
1862

1863
                    LRT_(info).format("dynamic loading succeeded: {}: {}",
×
1864
                        lib.string(), instance);
1865
                }
1866
                else
1867
                {
1868
                    LRT_(warning).format(
32✔
1869
                        "dynamic loading of plugin factory failed: {}: {}: {}",
×
1870
                        lib.string(), instance, get_error_what(ec));
1871
                }
1872
            }
1873

×
1874
            // make sure startup/shutdown registration is called once for each
1875
            // module, same for plugins
×
1876
            if (startup_handled.find(d.get_name()) == startup_handled.end())
1877
            {
1878
                startup_handled.insert(d.get_name());
1879
                load_commandline_options(d, options, ec);
1880
                if (ec)
1881
                    ec = error_code(throwmode::lightweight);
32✔
1882
                load_startup_shutdown_functions(d, ec);
1883
            }
1884
        }
32✔
1885
        catch (hpx::exception const&)
32✔
1886
        {
64✔
1887
            throw;
32✔
1888
        }
1889
        catch (std::logic_error const& e)
1890
        {
×
1891
            LRT_(warning).format("dynamic loading failed: {}: {}: {}",
1892
                lib.string(), instance, e.what());
×
1893
            return false;
×
1894
        }
×
1895
        catch (std::exception const& e)
1896
        {
×
1897
            LRT_(warning).format("dynamic loading failed: {}: {}: {}",
×
1898
                lib.string(), instance, e.what());
1899
            return false;
×
1900
        }
×
1901
        return true;
1902
    }
×
1903

×
1904
    bool runtime_support::load_plugin_dynamic(util::section& ini,
1905
        std::string const& instance, std::string const& plugin,
×
1906
        filesystem::path lib, bool isenabled,
32✔
1907
        hpx::program_options::options_description& options,
1908
        std::set<std::string>& startup_handled)
1909
    {
32✔
1910
        auto it = modules_.find(HPX_MANGLE_STRING(plugin));
1911
        if (it != modules_.cend())
1912
        {
1913
            // use loaded module, instantiate the requested factory
1914
            return load_plugin((*it).second, ini, instance, plugin, lib,
1915
                isenabled, options, startup_handled);
32✔
1916
        }
32✔
1917

1918
        // get the handle of the library
1919
        error_code ec(throwmode::lightweight);
32✔
1920
        hpx::util::plugin::dll d(lib.string(), HPX_MANGLE_STRING(plugin));
1921
        d.load_library(ec);
1922
        if (ec)
1923
        {
1924
            // build path to component to load
1925
            std::string libname(HPX_MAKE_DLL_STRING(plugin));
×
1926
            lib /= filesystem::path(libname);
1927
            d.load_library(ec);
×
1928
            if (ec)
1929
            {
1930
                LRT_(warning).format("dynamic loading failed: {}: {}: {}",
×
1931
                    lib.string(), instance, get_error_what(ec));
×
1932
                return false;    // next please :-P
1933
            }
×
1934
        }
1935

×
1936
        // now, instantiate the requested factory
×
1937
        if (!load_plugin(d, ini, instance, plugin, lib, isenabled, options,
1938
                startup_handled))
1939
        {
1940
            return false;    // next please :-P
1941
        }
1942

×
1943
        modules_.emplace(HPX_MANGLE_STRING(plugin), d);
1944
        return true;    // plugin got loaded
1945
    }
1946
#endif
1947
}}}    // namespace hpx::components::server
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