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

STEllAR-GROUP / hpx / #845

05 Dec 2022 08:25PM UTC coverage: 85.664% (-0.1%) from 85.8%
#845

push

StellarBot
Merge #6091

6091: Replace artificial sequencing with fold expressions r=hkaiser a=hkaiser

- flyby: fix left-over problems from namespace change

working towards resolving #5497

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

99 of 99 new or added lines in 15 files covered. (100.0%)

171125 of 199764 relevant lines covered (85.66%)

1865254.07 hits per line

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

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

7
#include <hpx/config.hpp>
8
#include <hpx/assert.hpp>
9
#include <hpx/coroutines/coroutine.hpp>
10
#include <hpx/functional/bind.hpp>
11
#include <hpx/modules/errors.hpp>
12
#include <hpx/modules/format.hpp>
13
#include <hpx/modules/logging.hpp>
14
#include <hpx/threading_base/create_work.hpp>
15
#include <hpx/threading_base/register_thread.hpp>
16
#include <hpx/threading_base/set_thread_state.hpp>
17
#include <hpx/threading_base/thread_data.hpp>
18
#include <hpx/threading_base/threading_base_fwd.hpp>
19

20
#include <cstddef>
21
#include <functional>
22
#include <string>
23
#include <utility>
24

25
namespace hpx { namespace threads { namespace detail {
26

27
    ///////////////////////////////////////////////////////////////////////////
28
    thread_result_type set_active_state(thread_id_ref_type thrd,
60✔
29
        thread_schedule_state newstate, thread_restart_state newstate_ex,
30
        thread_priority priority, thread_state previous_state)
31
    {
32
        if (HPX_UNLIKELY(!thrd))
60✔
33
        {
34
            HPX_THROW_EXCEPTION(null_thread_id,
×
35
                "threads::detail::set_active_state",
36
                "null thread id encountered");
37
            return thread_result_type(
38
                thread_schedule_state::terminated, invalid_thread_id);
39
        }
40

41
        // make sure that the thread has not been suspended and set active again
42
        // in the meantime
43
        thread_state current_state = get_thread_id_data(thrd)->get_state();
60✔
44

45
        if (current_state.state() == previous_state.state() &&
60✔
46
            current_state != previous_state)
13✔
47
        {
48
            // NOLINTNEXTLINE(bugprone-branch-clone)
49
            LTM_(warning).format(
×
50
                "set_active_state: thread is still active, however it was "
×
51
                "non-active since the original set_state request was issued, "
52
                "aborting state change, thread({}), description({}), new "
53
                "state({})",
54
                thrd, get_thread_id_data(thrd)->get_description(),
×
55
                get_thread_state_name(newstate));
×
56
            return thread_result_type(
×
57
                thread_schedule_state::terminated, invalid_thread_id);
×
58
        }
59

60
        // just retry, set_state will create new thread if target is still active
61
        error_code ec(throwmode::lightweight);    // do not throw
60✔
62
        detail::set_thread_state(thrd.noref(), newstate, newstate_ex, priority,
120✔
63
            thread_schedule_hint(), true, ec);
60✔
64

65
        return thread_result_type(
60✔
66
            thread_schedule_state::terminated, invalid_thread_id);
60✔
67
    }
60✔
68

69
    ///////////////////////////////////////////////////////////////////////////
70
    thread_state set_thread_state(thread_id_type const& thrd,
1,153,012✔
71
        thread_schedule_state new_state, thread_restart_state new_state_ex,
72
        thread_priority priority, thread_schedule_hint schedulehint,
73
        bool retry_on_active, error_code& ec)
74
    {
75
        if (HPX_UNLIKELY(!thrd))
1,153,014✔
76
        {
77
            HPX_THROWS_IF(ec, null_thread_id,
52✔
78
                "threads::detail::set_thread_state",
79
                "null thread id encountered");
80
            return thread_state(
×
81
                thread_schedule_state::unknown, thread_restart_state::unknown);
82
        }
83

84
        // set_state can't be used to force a thread into active state
85
        if (new_state == thread_schedule_state::active)
1,153,010✔
86
        {
87
            HPX_THROWS_IF(ec, bad_parameter,
×
88
                "threads::detail::set_thread_state", "invalid new state: {}",
89
                new_state);
90
            return thread_state(
×
91
                thread_schedule_state::unknown, thread_restart_state::unknown);
92
        }
93

94
        thread_state previous_state;
1,153,012✔
95
        std::size_t k = 0;
1,153,012✔
96
        do
1,153,012✔
97
        {
98
            // action depends on the current state
99
            previous_state = get_thread_id_data(thrd)->get_state();
1,156,055✔
100
            thread_schedule_state previous_state_val = previous_state.state();
1,156,055✔
101

102
            // nothing to do here if the state doesn't change
103
            if (new_state == previous_state_val)
1,156,055✔
104
            {
105
                // NOLINTNEXTLINE(bugprone-branch-clone)
106
                LTM_(warning).format(
350✔
107
                    "set_thread_state: old thread state is the same as new "
175✔
108
                    "thread state, aborting state change, thread({}), "
109
                    "description({}), new state({})",
110
                    thrd, get_thread_id_data(thrd)->get_description(),
175✔
111
                    get_thread_state_name(new_state));
175✔
112

113
                if (&ec != &throws)
175✔
114
                    ec = make_success_code();
×
115

116
                return thread_state(new_state, previous_state.state_ex());
175✔
117
            }
118

119
            // the thread to set the state for is currently running, so we
120
            // schedule another thread to execute the pending set_state
121
            switch (previous_state_val)
1,155,879✔
122
            {
123
            case thread_schedule_state::active:
124
            {
125
                if (retry_on_active)
3,108✔
126
                {
127
                    // schedule a new thread to set the state
128
                    // NOLINTNEXTLINE(bugprone-branch-clone)
129
                    LTM_(warning).format(
102✔
130
                        "set_thread_state: thread is currently active, "
42✔
131
                        "scheduling new thread, thread({}), description({}), "
132
                        "new state({})",
133
                        thrd, get_thread_id_data(thrd)->get_description(),
42✔
134
                        get_thread_state_name(new_state));
42✔
135

136
                    thread_init_data data(
60✔
137
                        hpx::bind(&set_active_state, thread_id_ref_type(thrd),
60✔
138
                            new_state, new_state_ex, priority, previous_state),
139
                        "set state for active thread", priority);
60✔
140

141
                    create_work(get_thread_id_data(thrd)->get_scheduler_base(),
60✔
142
                        data, ec);
60✔
143

144
                    if (&ec != &throws)
60✔
145
                        ec = make_success_code();
13✔
146
                }
60✔
147
                else
148
                {
149
                    hpx::execution_base::this_thread::yield_k(
3,048✔
150
                        k, "hpx::threads::detail::set_thread_state");
3,048✔
151
                    ++k;
3,048✔
152

153
                    // NOLINTNEXTLINE(bugprone-branch-clone)
154
                    LTM_(warning).format(
6,096✔
155
                        "set_thread_state: thread is currently active, but not "
3,048✔
156
                        "scheduling new thread because retry_on_active = "
157
                        "false, thread({}), description({}), new state({})",
158
                        thrd, get_thread_id_data(thrd)->get_description(),
3,048✔
159
                        get_thread_state_name(new_state));
3,048✔
160

161
                    continue;
3,048✔
162
                }
163

164
                if (&ec != &throws)
60✔
165
                    ec = make_success_code();
13✔
166

167
                return previous_state;    // done
60✔
168
            }
169
            break;
170
            case thread_schedule_state::terminated:
171
            {
172
                // NOLINTNEXTLINE(bugprone-branch-clone)
173
                LTM_(warning).format(
4✔
174
                    "set_thread_state: thread is terminated, aborting state "
2✔
175
                    "change, thread({}), description({}), new state({})",
176
                    thrd, get_thread_id_data(thrd)->get_description(),
2✔
177
                    get_thread_state_name(new_state));
2✔
178

179
                if (&ec != &throws)
2✔
180
                    ec = make_success_code();
×
181

182
                // If the thread has been terminated while this set_state was
183
                // pending nothing has to be done anymore.
184
                return previous_state;
2✔
185
            }
52✔
186
            break;
187
            case thread_schedule_state::pending:
188
                [[fallthrough]];
189
            case thread_schedule_state::pending_boost:
190
                if (thread_schedule_state::suspended == new_state)
52✔
191
                {
192
                    // we do not allow explicit resetting of a state to suspended
193
                    // without the thread being executed.
194
                    std::string str = hpx::util::format(
52✔
195
                        "set_thread_state: invalid new state, can't demote a "
52✔
196
                        "pending thread, thread({}), description({}), new "
197
                        "state({})",
198
                        thrd, get_thread_id_data(thrd)->get_description(),
52✔
199
                        new_state);
200

201
                    // NOLINTNEXTLINE(bugprone-branch-clone)
202
                    LTM_(fatal) << str;
52✔
203

204
                    HPX_THROWS_IF(ec, bad_parameter,
52✔
205
                        "threads::detail::set_thread_state", str);
206
                    return thread_state(thread_schedule_state::unknown,
×
207
                        thread_restart_state::unknown);
208
                }
52✔
209
                break;
×
210
            case thread_schedule_state::suspended:
211
                break;    // fine, just set the new state
1,152,717✔
212
            case thread_schedule_state::pending_do_not_schedule:
213
                [[fallthrough]];
214
            default:
215
            {
216
                HPX_ASSERT_MSG(false,
×
217
                    hpx::util::format("set_thread_state: previous state was {}",
218
                        previous_state_val));    // should not happen
219
                break;
×
220
            }
221
            }
222

223
            // If the previous state was pending we are supposed to remove the
224
            // thread from the queue. But in order to avoid linearly looking
225
            // through the queue we defer this to the thread function, which
226
            // at some point will ignore this thread by simply skipping it
227
            // (if it's not pending anymore).
228

229
            // NOLINTNEXTLINE(bugprone-branch-clone)
230
            LTM_(info).format("set_thread_state: thread({}), description({}), "
2,305,204✔
231
                              "new state({}), old state({})",
232
                thrd, get_thread_id_data(thrd)->get_description(),
1,152,495✔
233
                get_thread_state_name(new_state),
1,152,491✔
234
                get_thread_state_name(previous_state_val));
1,152,490✔
235

236
            // So all what we do here is to set the new state.
237
            if (get_thread_id_data(thrd)->restore_state(
2,305,466✔
238
                    new_state, new_state_ex, previous_state))
1,152,733✔
239
            {
240
                break;
1,152,733✔
241
            }
242

243
            // state has changed since we fetched it from the thread, retry
244
            // NOLINTNEXTLINE(bugprone-branch-clone)
245
            LTM_(warning).format(
×
246
                "set_thread_state: state has been changed since it was "
×
247
                "fetched, retrying, thread({}), description({}), new "
248
                "state({}), old state({})",
249
                get_thread_id_data(thrd),
×
250
                get_thread_id_data(thrd)->get_description(),
×
251
                get_thread_state_name(new_state),
×
252
                get_thread_state_name(previous_state_val));
×
253
        } while (true);
3,048✔
254

255
        thread_schedule_state previous_state_val = previous_state.state();
1,152,733✔
256
        if (!(previous_state_val == thread_schedule_state::pending ||
1,152,733✔
257
                previous_state_val == thread_schedule_state::pending_boost) &&
1,152,733✔
258
            (new_state == thread_schedule_state::pending ||
1,152,733✔
259
                new_state == thread_schedule_state::pending_boost))
×
260
        {
261
            // REVIEW: Passing a specific target thread may interfere with the
262
            // round robin queuing.
263

264
            auto* thrd_data = get_thread_id_data(thrd);
1,152,733✔
265
            auto* scheduler = thrd_data->get_scheduler_base();
1,152,733✔
266
            scheduler->schedule_thread(
2,305,466✔
267
                thrd, schedulehint, false, thrd_data->get_priority());
1,152,733✔
268
            // NOTE: Don't care if the hint is a NUMA hint, just want to wake up
269
            // a thread.
270
            scheduler->do_some_work(schedulehint.hint);
1,152,731✔
271
        }
1,152,731✔
272

273
        if (&ec != &throws)
1,152,732✔
274
            ec = make_success_code();
12,127✔
275

276
        return previous_state;
1,152,732✔
277
    }
1,153,021✔
278
}}}    // namespace hpx::threads::detail
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