• 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

95.0
/libs/core/execution_base/include/hpx/execution_base/this_thread.hpp
1
//  Copyright (c) 2019 Thomas Heller
2
//  Copyright (c) 2022 Hartmut Kaiser
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
#pragma once
9

10
#include <hpx/config.hpp>
11
#include <hpx/execution_base/agent_base.hpp>
12
#include <hpx/execution_base/agent_ref.hpp>
13
#include <hpx/execution_base/sender.hpp>
14
#include <hpx/modules/tag_invoke.hpp>
15
#include <hpx/modules/timing.hpp>
16
#include <hpx/modules/type_support.hpp>
17

18
#ifdef HPX_HAVE_SPINLOCK_DEADLOCK_DETECTION
19
#include <hpx/execution_base/detail/spinlock_deadlock_detection.hpp>
20
#include <hpx/modules/errors.hpp>
21
#endif
22

23
#include <chrono>
24
#include <cstddef>
25
#include <cstdint>
26

27
namespace hpx::execution_base {
28

29
    namespace detail {
30

31
        HPX_CXX_EXPORT HPX_CORE_EXPORT agent_base& get_default_agent();
32
    }
33

34
    ///////////////////////////////////////////////////////////////////////////
35
    namespace this_thread {
36

37
        namespace detail {
38

39
            HPX_CXX_EXPORT struct agent_storage;
40
            HPX_CXX_EXPORT HPX_CORE_EXPORT agent_storage* get_agent_storage();
41
        }    // namespace detail
42

43
        HPX_CXX_EXPORT struct HPX_CORE_EXPORT reset_agent
44
        {
45
            explicit reset_agent(agent_base& impl);
46
            reset_agent(detail::agent_storage*, agent_base& impl);
47

48
            reset_agent(reset_agent const&) = delete;
49
            reset_agent(reset_agent&&) = delete;
50
            reset_agent& operator=(reset_agent const&) = delete;
51
            reset_agent& operator=(reset_agent&&) = delete;
52

53
            ~reset_agent();
54

55
            detail::agent_storage* storage_;
56
            agent_base* old_;
57
        };
58

59
        HPX_CXX_EXPORT HPX_CORE_EXPORT hpx::execution_base::agent_ref agent();
60

61
        HPX_CXX_EXPORT HPX_CORE_EXPORT void yield(
62
            char const* desc = "hpx::execution_base::this_thread::yield");
63
        HPX_CXX_EXPORT HPX_CORE_EXPORT bool yield_k(std::size_t k,
64
            char const* desc = "hpx::execution_base::this_thread::yield_k");
65
        HPX_CXX_EXPORT HPX_CORE_EXPORT void suspend(
66
            char const* desc = "hpx::execution_base::this_thread::suspend");
67

68
        HPX_CXX_EXPORT template <typename Rep, typename Period>
69
        void sleep_for(std::chrono::duration<Rep, Period> const& sleep_duration,
70
            char const* desc = "hpx::execution_base::this_thread::sleep_for")
71
        {
72
            agent().sleep_for(sleep_duration, desc);
73
        }
74

75
        HPX_CXX_EXPORT template <class Clock, class Duration>
76
        void sleep_until(
77
            std::chrono::time_point<Clock, Duration> const& sleep_time,
78
            char const* desc = "hpx::execution_base::this_thread::sleep_for")
79
        {
80
            agent().sleep_until(sleep_time, desc);
81
        }
82
    }    // namespace this_thread
83
}    // namespace hpx::execution_base
84

85
#if defined(HPX_HAVE_STDEXEC)
86

87
#include <hpx/modules/execution_base.hpp>
88

89
namespace hpx::this_thread::experimental {
90

91
    using namespace std::this_thread;
92
    HPX_CXX_EXPORT using stdexec::execute_may_block_caller;
93
    HPX_CXX_EXPORT using stdexec::execute_may_block_caller_t;
94

95
    // this_thread::sync_wait is loaded in the sync_wait.hpp file.
96
}    // namespace hpx::this_thread::experimental
97

98
#else
99

100
namespace hpx::this_thread::experimental {
101

102
    // [exec.sched_queries.execute_may_block_caller]
103
    //
104
    // 1. `this_thread::execute_may_block_caller` is used to ask a scheduler s
105
    // whether a call `execution::execute(s, f)` with any invocable f may block
106
    // the thread where such a call occurs.
107
    //
108
    // 2. The name `this_thread::execute_may_block_caller` denotes a
109
    // customization point object. For some subexpression s, let S be
110
    // decltype((s)). If S does not satisfy `execution::scheduler`,
111
    // `this_thread::execute_may_block_caller` is ill-formed. Otherwise,
112
    // `this_thread::execute_may_block_caller(s)` is expression equivalent to:
113
    //
114
    //      1. `tag_invoke(this_thread::execute_may_block_caller, as_const(s))`,
115
    //          if this expression is well-formed.
116
    //
117
    //          -- Mandates: The tag_invoke expression above is not
118
    //                       potentially throwing and its type is bool.
119
    //
120
    //      2. Otherwise, true.
121
    //
122
    // 3. If `this_thread::execute_may_block_caller(s)` for some scheduler s
123
    // returns false, no execution::execute(s, f) call with some invocable f
124
    // shall block the calling thread.
125
    namespace detail {
126

127
        // apply this meta function to all tag_invoke variations
128
        struct is_scheduler
129
        {
130
            template <typename EnableTag, typename... T>
131
            using apply = hpx::execution::experimental::is_scheduler<T...>;
132
        };
133
    }    // namespace detail
134

135
    HPX_CXX_EXPORT HPX_HOST_DEVICE_INLINE_CONSTEXPR_VARIABLE struct
136
        execute_may_block_caller_t final
137
      : hpx::functional::detail::tag_fallback_noexcept<
138
            execute_may_block_caller_t, detail::is_scheduler>
139
    {
140
    private:
141
        template <typename T>
142
        friend constexpr HPX_FORCEINLINE bool tag_fallback_invoke(
143
            execute_may_block_caller_t, T const&) noexcept
144
        {
145
            return true;
146
        }
147
    } execute_may_block_caller{};
148
}    // namespace hpx::this_thread::experimental
149

150
#endif
47,437✔
151

1,907✔
152
namespace hpx::util {
153

154
    namespace detail {
155

24,425✔
156
        HPX_CXX_EXPORT inline bool yield_k(
157
            std::size_t k, char const* thread_name)
100,463✔
158
        {
159
#ifdef HPX_HAVE_SPINLOCK_DEADLOCK_DETECTION
160
            if (k > 32 && get_spinlock_break_on_deadlock_enabled() &&
161
                k > get_spinlock_deadlock_detection_limit())
162
            {
163
                HPX_THROW_EXCEPTION(hpx::error::deadlock, thread_name,
164
                    "possible deadlock detected");
165
            }
166
#endif
167
            return hpx::execution_base::this_thread::yield_k(k, thread_name);
168
        }
24,425✔
169
    }    // namespace detail
170

171
    HPX_CXX_EXPORT template <bool AllowTimedSuspension, typename Predicate>
172
    void yield_while(Predicate&& predicate, char const* thread_name = nullptr)
173
    {
174
        for (std::size_t k = 0; predicate(); ++k)
175
        {
176
            if constexpr (AllowTimedSuspension)
541✔
177
            {
178
                detail::yield_k(k, thread_name);
179
            }
180
            else
181
            {
182
                detail::yield_k(k % 16, thread_name);
183
            }
184
        }
185
    }
186

187
    HPX_CXX_EXPORT template <typename Predicate>
188
    void yield_while(Predicate&& predicate, char const* thread_name = nullptr,
189
        bool allow_timed_suspension = true)
190
    {
191
        if (allow_timed_suspension)
192
        {
193
            yield_while<true>(HPX_FORWARD(Predicate, predicate), thread_name);
194
        }
195
        else
84✔
196
        {
197
            yield_while<false>(HPX_FORWARD(Predicate, predicate), thread_name);
198
        }
199
    }
200

1,164✔
201
    namespace detail {
202

1,248✔
203
        // yield_while_count yields until the predicate returns true
204
        // required_count times consecutively. This function is used in cases
927✔
205
        // where there is a small false positive rate and repeatedly calling the
206
        // predicate reduces the rate of false positives overall.
84✔
207
        //
208
        // Note: This is mostly a hack used to work around the raciness of
209
        // termination detection for thread pools and the runtime and can be
210
        // replaced if and when a better solution appears.
211
        HPX_CXX_EXPORT template <typename Predicate>
212
        void yield_while_count(Predicate&& predicate,
321✔
213
            std::size_t required_count, char const* thread_name = nullptr,
214
            bool allow_timed_suspension = true)
215
        {
216
            std::size_t count = 0;
217
            for (std::size_t k = 0; /**/; ++k)
218
            {
219
                if (!predicate())
220
                {
221
                    if (++count > required_count)
222
                    {
223
                        return;
56✔
224
                    }
225
                }
226
                else
227
                {
228
                    count = 0;
229
                    detail::yield_k(
230
                        allow_timed_suspension ? k : k % 16, thread_name);
231
                }
232
            }
233
        }
234

235
        // yield_while_count_timeout is similar to yield_while_count, with the
236
        // addition of a timeout parameter. If the timeout is exceeded, waiting
240✔
237
        // is stopped and the function returns false. If the predicate is
238
        // successfully waited for the function returns true.
592✔
239
        HPX_CXX_EXPORT template <typename Predicate>
560✔
240
        bool yield_while_count_timeout(Predicate&& predicate,
241
            std::size_t required_count,
32✔
242
            hpx::chrono::steady_duration const& rel_time,
243
            char const* thread_name = nullptr,
244
            bool allow_timed_suspension = true)
264✔
245
        {
246
            // Initialize timer only if needed
264✔
247
            bool const use_timeout =
248
                rel_time.value() != std::chrono::steady_clock::duration(0);
249

250
            auto const abs_time = rel_time.from_now();
251

252
            std::size_t count = 0;
253
            for (std::size_t k = 0; /**/; ++k)
254
            {
×
255
                if (use_timeout &&
256
                    abs_time <= std::chrono::steady_clock().now())
257
                {
258
                    return false;
259
                }
260

261
                if (!predicate())
262
                {
263
                    if (++count > required_count)
264
                    {
265
                        return true;
266
                    }
267
                }
268
                else
269
                {
270
                    count = 0;
271
                    detail::yield_k(
272
                        allow_timed_suspension ? k : k % 16, thread_name);
273
                }
274
            }
275
        }
276
    }    // namespace detail
277
}    // namespace hpx::util
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

© 2026 Coveralls, Inc