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

STEllAR-GROUP / hpx / #876

26 Jan 2023 04:24PM UTC coverage: 86.427% (+0.04%) from 86.39%
#876

push

StellarBot
Merge #6154

6154: Avoid performing late command line handling twice in distributed runtime r=hkaiser a=hkaiser

`@weilewei` this should fix the issue you were seeing (`--hpx:print-bind` being invoked twice)

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

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

174557 of 201970 relevant lines covered (86.43%)

1972404.34 hits per line

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

96.43
/examples/quickstart/init_globally.cpp
1
//  Copyright (c) 2016-2022 Hartmut Kaiser
2
//
3
//  SPDX-License-Identifier: BSL-1.0
4
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
5
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6

7
// This example demonstrates several things:
8
//
9
// - How to initialize (and terminate) the HPX runtime from a global object
10
//   (see the type `manage_global_runtime' below)
11
// - How to register and unregister any (kernel) thread with the HPX runtime
12
// - How to launch an HPX thread from any (registered) kernel thread and
13
//   how to wait for the HPX thread to run to completion before continuing.
14
//   Any value returned from the HPX thread will be marshaled back to the
15
//   calling (kernel) thread.
16
//
17
// This scheme is generally useful if HPX should be initialized from a shared
18
// library and the main executable might not even be aware of this.
19

20
#include <hpx/init.hpp>
21
#include <hpx/local/condition_variable.hpp>
22
#include <hpx/local/functional.hpp>
23
#include <hpx/local/mutex.hpp>
24
#include <hpx/local/runtime.hpp>
25
#include <hpx/local/thread.hpp>
26
#include <hpx/runtime_local/run_as_hpx_thread.hpp>
27

28
#include <mutex>
29
#include <string>
30
#include <vector>
31

32
///////////////////////////////////////////////////////////////////////////////
33
// Store the command line arguments in global variables to make them available
34
// to the startup code.
35

36
#if defined(linux) || defined(__linux) || defined(__linux__)
37

38
int __argc = 0;
39
char** __argv = nullptr;
40

41
void set_argc_argv(int argc, char* argv[], char*[])
1✔
42
{
43
    __argc = argc;
1✔
44
    __argv = argv;
1✔
45
}
1✔
46

47
__attribute__((section(".preinit_array"))) void (*set_global_argc_argv)(
48
    int, char*[], char*[]) = &set_argc_argv;
49

50
#elif defined(__APPLE__)
51

52
#include <crt_externs.h>
53

54
inline int get_arraylen(char** argv)
55
{
56
    int count = 0;
57
    if (nullptr != argv)
58
    {
59
        while (nullptr != argv[count])
60
            ++count;
61
    }
62
    return count;
63
}
64

65
int __argc = get_arraylen(*_NSGetArgv());
66
char** __argv = *_NSGetArgv();
67

68
#endif
69

70
class manage_global_runtime_impl
71
{
72
public:
73
    manage_global_runtime_impl()
1✔
74
      : running_(false)
1✔
75
      , rts_(nullptr)
1✔
76
    {
77
#if defined(HPX_WINDOWS)
78
        hpx::detail::init_winsocket();
79
#endif
80

81
        std::vector<std::string> const cfg = {
3✔
82
            // make sure hpx_main is always executed
83
            "hpx.run_hpx_main!=1",
1✔
84
            // allow for unknown command line options
85
            "hpx.commandline.allow_unknown!=1",
1✔
86
            // disable HPX' short options
87
            "hpx.commandline.aliasing!=0"};
1✔
88

89
        using hpx::placeholders::_1;
90
        using hpx::placeholders::_2;
91
        hpx::function<int(int, char**)> start_function =
92
            hpx::bind(&manage_global_runtime_impl::hpx_main, this, _1, _2);
1✔
93
        hpx::init_params init_args;
1✔
94
        init_args.cfg = cfg;
1✔
95
        init_args.mode = hpx::runtime_mode::default_;
1✔
96

97
        if (!hpx::start(start_function, __argc, __argv, init_args))
1✔
98
        {
99
            // Something went wrong while initializing the runtime.
100
            // This early we can't generate any output, just bail out.
101
            std::abort();
×
102
        }
103

104
        // Wait for the main HPX thread (hpx_main below) to have started running
105
        std::unique_lock<std::mutex> lk(startup_mtx_);
1✔
106
        while (!running_)
1✔
107
            startup_cond_.wait(lk);
×
108
    }
1✔
109

110
    ~manage_global_runtime_impl()
1✔
111
    {
112
        // notify hpx_main above to tear down the runtime
113
        {
114
            std::lock_guard<hpx::spinlock> lk(mtx_);
1✔
115
            rts_ = nullptr;    // reset pointer
1✔
116
        }
1✔
117

118
        cond_.notify_one();    // signal exit
1✔
119

120
        // wait for the runtime to exit
121
        hpx::stop();
1✔
122
    }
1✔
123

124
    // registration of external (to HPX) threads
125
    void register_thread(char const* name)
1✔
126
    {
127
        hpx::register_thread(rts_, name);
1✔
128
    }
1✔
129
    void unregister_thread()
1✔
130
    {
131
        hpx::unregister_thread(rts_);
1✔
132
    }
1✔
133

134
protected:
135
    // Main HPX thread, does nothing but wait for the application to exit
136
    int hpx_main(int, char*[])
1✔
137
    {
138
        // Store a pointer to the runtime here.
139
        rts_ = hpx::get_runtime_ptr();
1✔
140

141
        // Signal to constructor that thread has started running.
142
        {
143
            std::lock_guard<std::mutex> lk(startup_mtx_);
1✔
144
            running_ = true;
1✔
145
        }
1✔
146

147
        startup_cond_.notify_one();
1✔
148

149
        // Here other HPX specific functionality could be invoked...
150

151
        // Now, wait for destructor to be called.
152
        {
153
            std::unique_lock<hpx::spinlock> lk(mtx_);
1✔
154
            if (rts_ != nullptr)
1✔
155
                cond_.wait(lk);
1✔
156
        }
1✔
157

158
        // tell the runtime it's ok to exit
159
        return hpx::finalize();
1✔
160
    }
×
161

162
private:
163
    hpx::spinlock mtx_;
164
    hpx::condition_variable_any cond_;
165

166
    std::mutex startup_mtx_;
167
    std::condition_variable startup_cond_;
168
    bool running_;
169

170
    hpx::runtime* rts_;
171
};
172

173
// This class demonstrates how to initialize a console instance of HPX
174
// (locality 0). In order to create an HPX instance which connects to a running
175
// HPX application two changes have to be made:
176
//
177
//  - replace hpx::runtime_mode::default_ with hpx::runtime_mode::connect
178
//  - replace hpx::finalize() with hpx::disconnect()
179
//
180
// Note that the mode runtime_mode::default_ corresponds to runtime_mode::console
181
// if the distributed runtime is enabled, and runtime_mode::local otherwise.
182
//
183
// The separation of the implementation into manage_global_runtime and
184
// manage_global_runtime_impl ensures that the manage_global_runtime_impl
185
// destructor is called before the thread_local default agent is destructed,
186
// allowing the former to call yield if necessary while waiting for the runtime
187
// to shut down. This is done by accessing the default agent before accessing
188
// the manage_global_runtime object. Although the latter is thread_local, only
189
// one instance will be created. It is thread_local only to ensure the correct
190
// sequencing of destructors.
191
class manage_global_runtime
1✔
192
{
193
    manage_global_runtime_impl& get()
1✔
194
    {
195
        static thread_local manage_global_runtime_impl m;
1✔
196
        return m;
1✔
197
    }
198

199
    hpx::execution_base::agent_base& agent =
2✔
200
        hpx::execution_base::detail::get_default_agent();
1✔
201
    manage_global_runtime_impl& m = get();
1✔
202

203
public:
204
    void register_thread(char const* name)
1✔
205
    {
206
        m.register_thread(name);
1✔
207
    }
1✔
208

209
    void unregister_thread()
1✔
210
    {
211
        m.unregister_thread();
1✔
212
    }
1✔
213
};
214

215
// This global object will initialize HPX in its constructor and make sure HPX
216
// stops running in its destructor.
217
manage_global_runtime init;
1✔
218

219
///////////////////////////////////////////////////////////////////////////////
220
struct thread_registration_wrapper
221
{
222
    thread_registration_wrapper(char const* name)
1✔
223
    {
224
        // Register this thread with HPX, this should be done once for
225
        // each external OS-thread intended to invoke HPX functionality.
226
        // Calling this function more than once will silently fail (will
227
        // return false).
228
        init.register_thread(name);
1✔
229
    }
1✔
230
    ~thread_registration_wrapper()
1✔
231
    {
232
        // Unregister the thread from HPX, this should be done once in the
233
        // end before the external thread exists.
234
        init.unregister_thread();
1✔
235
    }
1✔
236
};
237

238
///////////////////////////////////////////////////////////////////////////////
239
// These functions will be executed as HPX threads.
240
void hpx_thread_func1()
2✔
241
{
242
    // All of the HPX functionality is available here, including hpx::async,
243
    // hpx::future, and friends.
244

245
    // As an example, just sleep for one second.
246
    hpx::this_thread::sleep_for(std::chrono::seconds(1));
2✔
247
}
2✔
248

249
int hpx_thread_func2(int arg)
1✔
250
{
251
    // All of the HPX functionality is available here, including hpx::async,
252
    // hpx::future, and friends.
253

254
    // As an example, just sleep for one second.
255
    hpx::this_thread::sleep_for(std::chrono::seconds(1));
1✔
256

257
    // Simply return the argument.
258
    return arg;
1✔
259
}
260

261
///////////////////////////////////////////////////////////////////////////////
262
// This code will be executed by a system thread.
263
void thread_func()
1✔
264
{
265
    // Register this (kernel) thread with the HPX runtime (unregister at exit).
266
    // Use a unique name for each of the created threads (could be derived from
267
    // std::this_thread::get_id()).
268
    thread_registration_wrapper register_thread("thread_func");
1✔
269

270
    // Now, a limited number of HPX API functions can be called.
271

272
    // Create an HPX thread (returning an int) and wait for it to run to
273
    // completion.
274
    int result = hpx::threads::run_as_hpx_thread(&hpx_thread_func2, 42);
1✔
275

276
    // Create an HPX thread (returning void) and wait for it to run to
277
    // completion.
278
    if (result == 42)
1✔
279
        hpx::threads::run_as_hpx_thread(&hpx_thread_func1);
1✔
280
}
1✔
281

282
///////////////////////////////////////////////////////////////////////////////
283
int main()
1✔
284
{
285
    // Start a new (kernel) thread to demonstrate thread registration with HPX.
286
    std::thread t(&thread_func);
1✔
287

288
    // The main thread was automatically registered with the HPX runtime,
289
    // no explicit registration for this thread is necessary.
290
    hpx::threads::run_as_hpx_thread(&hpx_thread_func1);
1✔
291

292
    // wait for the (kernel) thread to run to completion
293
    t.join();
1✔
294

295
    return 0;
1✔
296
}
1✔
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