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

STEllAR-GROUP / hpx / #867

15 Jan 2023 08:00PM UTC coverage: 86.487% (+0.5%) from 85.951%
#867

push

StellarBot
Merge #6135

6135: Fixing warnings reported by MSVC analysis r=hkaiser a=hkaiser

- adding MSVC specific #pragma's to suppress the benign warnings


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

120 of 120 new or added lines in 33 files covered. (100.0%)

174599 of 201880 relevant lines covered (86.49%)

1945607.64 hits per line

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

63.64
/libs/core/synchronization/src/detail/condition_variable.cpp
1
//  Copyright (c) 2007-2023 Hartmut Kaiser
2
//  Copyright (c) 2013-2015 Agustin Berge
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/assert.hpp>
9
#include <hpx/execution_base/agent_ref.hpp>
10
#include <hpx/execution_base/this_thread.hpp>
11
#include <hpx/modules/errors.hpp>
12
#include <hpx/modules/logging.hpp>
13
#include <hpx/modules/memory.hpp>
14
#include <hpx/synchronization/detail/condition_variable.hpp>
15
#include <hpx/synchronization/no_mutex.hpp>
16
#include <hpx/synchronization/spinlock.hpp>
17
#include <hpx/thread_support/assert_owns_lock.hpp>
18
#include <hpx/thread_support/unlock_guard.hpp>
19
#include <hpx/threading_base/thread_helpers.hpp>
20
#include <hpx/timing/steady_clock.hpp>
21
#include <hpx/type_support/unused.hpp>
22

23
#include <cstddef>
24
#include <exception>
25
#include <mutex>
26
#include <utility>
27

28
namespace hpx::lcos::local::detail {
29

30
    ///////////////////////////////////////////////////////////////////////////
31
    struct condition_variable::queue_entry
32
    {
33
        constexpr queue_entry(
1,107,720✔
34
            hpx::execution_base::agent_ref ctx, void* q) noexcept
35
          : ctx_(ctx)
1,107,720✔
36
          , q_(q)
1,107,720✔
37
        {
38
        }
1,107,720✔
39

40
        hpx::execution_base::agent_ref ctx_;
41
        void* q_;
42

43
        queue_entry* next = nullptr;
1,107,720✔
44
        queue_entry* prev = nullptr;
1,107,720✔
45
    };
46

47
    struct condition_variable::reset_queue_entry
48
    {
49
        explicit constexpr reset_queue_entry(
1,107,723✔
50
            condition_variable::queue_entry& e) noexcept
51
          : e_(e)
1,107,723✔
52
        {
53
        }
1,107,723✔
54

55
        ~reset_queue_entry()
1,107,727✔
56
        {
57
            if (e_.ctx_)
1,107,727✔
58
            {
59
                condition_variable::queue_type* q =
36✔
60
                    static_cast<condition_variable::queue_type*>(e_.q_);
36✔
61
                q->erase(&e_);    // remove entry from queue
36✔
62
            }
36✔
63
        }
1,107,727✔
64

65
        condition_variable::queue_entry& e_;
66
    };
67

68
    ///////////////////////////////////////////////////////////////////////////
69
    condition_variable::~condition_variable()
5,165,871✔
70
    {
71
        if (!queue_.empty())
5,165,848✔
72
        {
73
            LERR_(fatal).format(
×
74
                "~condition_variable: queue is not empty, aborting threads");
×
75

76
            hpx::no_mutex no_mtx;
77
            std::unique_lock<hpx::no_mutex> lock(no_mtx);
×
78

79
            // Failing to release lock 'no_mtx' in function
80
#if defined(HPX_MSVC)
81
#pragma warning(push)
82
#pragma warning(disable : 26115)
83
#endif
84
            abort_all<hpx::no_mutex>(HPX_MOVE(lock));
×
85
#if defined(HPX_MSVC)
86
#pragma warning(pop)
87
#endif
88
        }
×
89
    }
5,165,848✔
90

91
    bool condition_variable::empty(
×
92
        [[maybe_unused]] std::unique_lock<mutex_type>& lock) const noexcept
93
    {
94
        HPX_ASSERT_OWNS_LOCK(lock);
×
95
        return queue_.empty();
×
96
    }
97

98
    std::size_t condition_variable::size(
10,227✔
99
        [[maybe_unused]] std::unique_lock<mutex_type>& lock) const noexcept
100
    {
101
        HPX_ASSERT_OWNS_LOCK(lock);
10,227✔
102
        return queue_.size();
10,227✔
103
    }
104

105
    // Return false if no more threads are waiting (returns true if queue
106
    // is non-empty).
107
    bool condition_variable::notify_one(std::unique_lock<mutex_type> lock,
5,984,532✔
108
        threads::thread_priority /* priority */, error_code& ec)
109
    {
110
        // Caller failing to hold lock 'lock' before calling function
111
#if defined(HPX_MSVC)
112
#pragma warning(push)
113
#pragma warning(disable : 26110)
114
#endif
115

116
        HPX_ASSERT_OWNS_LOCK(lock);
5,984,533✔
117

118
        if (!queue_.empty())
5,984,533✔
119
        {
120
            auto ctx = queue_.front()->ctx_;
1,028,710✔
121

122
            // remove item from queue before error handling
123
            queue_.front()->ctx_.reset();
1,028,710✔
124
            queue_.pop_front();
1,028,710✔
125

126
            if (HPX_UNLIKELY(!ctx))
1,028,710✔
127
            {
128
                lock.unlock();
×
129

130
                HPX_THROWS_IF(ec, hpx::error::null_thread_id,
×
131
                    "condition_variable::notify_one",
132
                    "null thread id encountered");
133
                return false;
×
134
            }
135

136
            bool not_empty = !queue_.empty();
1,028,720✔
137
            lock.unlock();
1,028,720✔
138

139
            ctx.resume();
1,028,720✔
140

141
            return not_empty;
1,028,720✔
142
        }
143

144
        if (&ec != &throws)
4,955,788✔
145
            ec = make_success_code();
×
146

147
        return false;
4,955,758✔
148

149
#if defined(HPX_MSVC)
150
#pragma warning(pop)
151
#endif
152
    }
5,984,478✔
153

154
    void condition_variable::notify_all(std::unique_lock<mutex_type> lock,
10,290✔
155
        threads::thread_priority /* priority */, error_code& ec)
156
    {
157
        // Caller failing to hold lock 'lock' before calling function
158
#if defined(HPX_MSVC)
159
#pragma warning(push)
160
#pragma warning(disable : 26110)
161
#endif
162
        HPX_ASSERT_OWNS_LOCK(lock);
10,290✔
163

164
        // swap the list
165
        queue_type queue;
10,290✔
166
        queue.swap(queue_);
10,290✔
167

168
        if (!queue.empty())
10,290✔
169
        {
170
            // update reference to queue for all queue entries
171
            for (queue_entry* qe = queue_.front(); qe != nullptr; qe = qe->next)
8,029✔
172
            {
173
                qe->q_ = &queue;    //-V506
×
174
            }
×
175

176
            do
8,029✔
177
            {
178
                auto ctx = queue.front()->ctx_;
78,976✔
179

180
                // remove item from queue before error handling
181
                queue.front()->ctx_.reset();
78,976✔
182
                queue.pop_front();
78,976✔
183

184
                if (HPX_UNLIKELY(!ctx))
78,976✔
185
                {
186
                    prepend_entries(lock, queue);
×
187
                    lock.unlock();
×
188

189
                    HPX_THROWS_IF(ec, hpx::error::null_thread_id,
×
190
                        "condition_variable::notify_all",
191
                        "null thread id encountered");
192
                    return;
×
193
                }
194

195
                util::ignore_while_checking il(&lock);
78,976✔
196
                HPX_UNUSED(il);
78,976✔
197

198
                ctx.resume();
78,976✔
199

200
            } while (!queue.empty());
78,976✔
201
        }
8,029✔
202

203
        if (&ec != &throws)
10,290✔
204
            ec = make_success_code();
×
205

206
#if defined(HPX_MSVC)
207
#pragma warning(pop)
208
#endif
209
    }
10,290✔
210

211
    void condition_variable::abort_all(std::unique_lock<mutex_type> lock)
×
212
    {
213
        HPX_ASSERT_OWNS_LOCK(lock);
×
214

215
        abort_all<mutex_type>(HPX_MOVE(lock));
×
216
    }
×
217

218
    threads::thread_restart_state condition_variable::wait(
1,107,658✔
219
        std::unique_lock<mutex_type>& lock, char const* /* description */,
220
        error_code& /* ec */)
221
    {
222
        HPX_ASSERT_OWNS_LOCK(lock);
1,107,670✔
223

224
        // enqueue the request and block this thread
225
        auto this_ctx = hpx::execution_base::this_thread::agent();
1,107,670✔
226
        queue_entry f(this_ctx, &queue_);
1,107,670✔
227
        queue_.push_back(f);
1,107,670✔
228

229
        reset_queue_entry r(f);
1,107,670✔
230
        {
231
            // suspend this thread
232
            unlock_guard<std::unique_lock<mutex_type>> ul(lock);
1,107,670✔
233
            this_ctx.suspend();
1,107,670✔
234
        }
1,107,670✔
235

236
        return f.ctx_ ? threads::thread_restart_state::timeout :
1,107,670✔
237
                        threads::thread_restart_state::signaled;
238
    }
1,107,670✔
239

240
    threads::thread_restart_state condition_variable::wait_until(
62✔
241
        std::unique_lock<mutex_type>& lock,
242
        hpx::chrono::steady_time_point const& abs_time,
243
        char const* /* description */, error_code& /* ec */)
244
    {
245
        HPX_ASSERT_OWNS_LOCK(lock);
62✔
246

247
        // enqueue the request and block this thread
248
        auto this_ctx = hpx::execution_base::this_thread::agent();
62✔
249
        queue_entry f(this_ctx, &queue_);
62✔
250
        queue_.push_back(f);
62✔
251

252
        reset_queue_entry r(f);
62✔
253
        {
254
            // suspend this thread
255
            unlock_guard<std::unique_lock<mutex_type>> ul(lock);
62✔
256
            this_ctx.sleep_until(abs_time.value());
62✔
257
        }
62✔
258

259
        return f.ctx_ ? threads::thread_restart_state::timeout :
62✔
260
                        threads::thread_restart_state::signaled;
261
    }
62✔
262

263
    template <typename Mutex>
264
    void condition_variable::abort_all(std::unique_lock<Mutex> lock)
×
265
    {
266
        // new threads might have been added while we were notifying
267
        while (!queue_.empty())
×
268
        {
269
            // swap the list
270
            queue_type queue;
×
271
            queue.swap(queue_);
×
272

273
            // update reference to queue for all queue entries
274
            for (queue_entry* qe = queue_.front(); qe != nullptr; qe = qe->next)
×
275
            {
276
                qe->q_ = &queue;    //-V506
×
277
            }
×
278

279
            while (!queue.empty())
×
280
            {
281
                auto ctx = queue.front()->ctx_;
×
282

283
                // remove item from queue before error handling
284
                queue.front()->ctx_.reset();
×
285
                queue.pop_front();
×
286

287
                if (HPX_UNLIKELY(!ctx))
×
288
                {
289
                    LERR_(fatal).format("condition_variable::abort_all: null "
×
290
                                        "thread id encountered");
291
                    continue;
×
292
                }
293

294
                LERR_(fatal).format(
×
295
                    "condition_variable::abort_all: pending thread: {}", ctx);
×
296

297
                // unlock while notifying thread as this can suspend
298
                unlock_guard<std::unique_lock<Mutex>> unlock(lock);
×
299

300
                // forcefully abort thread, do not throw
301
                ctx.abort();
×
302
            }
×
303
        }
304
    }
×
305

306
    // re-add the remaining items to the original queue
307
    void condition_variable::prepend_entries(
×
308
        [[maybe_unused]] std::unique_lock<mutex_type>& lock,
309
        queue_type& queue) noexcept
310
    {
311
        HPX_ASSERT_OWNS_LOCK(lock);
×
312
        queue.splice(queue_);
×
313
        queue_.swap(queue);
×
314
    }
×
315

316
    ///////////////////////////////////////////////////////////////////////////
317
    void intrusive_ptr_add_ref(condition_variable_data* p) noexcept
4,528✔
318
    {
319
        ++p->count_;
4,528✔
320
    }
4,528✔
321

322
    void intrusive_ptr_release(condition_variable_data* p) noexcept
9,178✔
323
    {
324
        if (0 == --p->count_)
9,178✔
325
        {
326
            delete p;
4,650✔
327
        }
4,650✔
328
    }
9,178✔
329
}    // namespace hpx::lcos::local::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