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

jbaldwin / libcoro / 13474880847

22 Feb 2025 05:01PM UTC coverage: 86.067%. First build
13474880847

Pull #304

github

web-flow
Merge 4b372fb5f into eef5815cb
Pull Request #304: Feature/condition variable compiler fixes

119 of 136 new or added lines in 4 files covered. (87.5%)

1532 of 1780 relevant lines covered (86.07%)

3926954.63 hits per line

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

85.95
/src/condition_variable.cpp
1
#include "coro/condition_variable.hpp"
2
#include "coro/when_all.hpp"
3
#include "coro/when_any.hpp"
4

5
#include <cassert>
6

7
namespace coro
8
{
9

10
condition_variable::condition_variable(std::shared_ptr<io_scheduler> scheduler) : m_scheduler(scheduler)
4✔
11
{
12
}
4✔
13

14
void condition_variable::notify_one() noexcept
10,002✔
15
{
16
    assert(m_scheduler);
10,002✔
17

18
    if (auto waiter_guard = extract_one())
10,002✔
19
        m_scheduler->resume(waiter_guard.value()->m_awaiting_coroutine);
10,002✔
20
}
10,002✔
21

22
void condition_variable::notify_all() noexcept
4✔
23
{
24
    assert(m_scheduler);
4✔
25

26
    if (auto waiter_guard = extract_all())
4✔
27
    {
28
        auto* waiter = waiter_guard.value();
4✔
29
        do
30
        {
31
            auto* next = waiter->m_next.load(std::memory_order::acquire);
99✔
32
            m_scheduler->resume(waiter->m_awaiting_coroutine);
99✔
33
            waiter = next;
99✔
34
        } while (waiter);
99✔
35
    }
4✔
36
}
4✔
37

38
auto condition_variable::wait(scoped_lock& lock) -> task<void>
9,925✔
39
{
40
    using namespace std::chrono_literals;
41

42
    auto mtx = lock.get_mutex();
43
    lock.unlock();
44

45
    co_await wait_for_notify();
46

47
    auto ulock = co_await mtx->lock();
48
    lock       = std::move(ulock);
49
    co_return;
50
}
19,850✔
51

NEW
52
std::shared_ptr<io_scheduler> condition_variable::scheduler() const noexcept
×
53
{
NEW
54
    return m_scheduler;
×
55
}
56

NEW
57
void condition_variable::set_scheduler(std::shared_ptr<io_scheduler> scheduler)
×
58
{
NEW
59
    m_scheduler = scheduler;
×
NEW
60
}
×
61

62
auto condition_variable::wait_for_ms(scoped_lock& lock, const std::chrono::milliseconds duration)
51✔
63
    -> task<std::cv_status>
64
{
65
    auto mtx = lock.get_mutex();
66
    lock.unlock();
67

68
    auto result = co_await m_scheduler->schedule(wait_task(this), duration);
69

70
    auto ulock = co_await mtx->lock();
71
    lock       = std::move(ulock);
72
    co_return result.has_value() ? std::cv_status::no_timeout : std::cv_status::timeout;
73
}
102✔
74

75
auto condition_variable::wait_task(condition_variable* cv) -> task<bool>
51✔
76
{
77
    co_await cv->wait_for_notify();
78
    co_return true;
79
}
102✔
80

81
void condition_variable::lock(void* ptr) noexcept
19,807✔
82
{
83
    assert(ptr);
19,807✔
84

85
    while (true)
86
    {
87
        void* unlocked{};
107,893✔
88
        if (m_lock.compare_exchange_weak(unlocked, ptr, std::memory_order::acq_rel))
107,893✔
89
            break;
19,798✔
90
    }
88,086✔
91
}
19,798✔
92

93
void condition_variable::unlock() noexcept
19,961✔
94
{
95
    m_lock.store(nullptr, std::memory_order::release);
19,961✔
96
}
19,961✔
97

98
void condition_variable::insert_waiter(wait_operation* waiter) noexcept
10,027✔
99
{
100
    while (true)
101
    {
102
        wait_operation* current = m_internal_waiters.load(std::memory_order::acquire);
10,027✔
103
        waiter->m_next.store(current, std::memory_order::release);
10,025✔
104

105
        if (!m_internal_waiters.compare_exchange_weak(current, waiter, std::memory_order::acq_rel))
10,027✔
106
            continue;
52✔
107

108
        break;
9,976✔
109
    }
52✔
110
}
9,976✔
111

112
bool condition_variable::extract_waiter(wait_operation* waiter) noexcept
9,946✔
113
{
114
    cv_lock_guard guard{this};
9,946✔
115
    bool          result{};
9,955✔
116

117
    while (true)
118
    {
119
        wait_operation* current = m_internal_waiters.load(std::memory_order::acquire);
9,955✔
120

121
        if (!current)
9,955✔
122
            break;
208✔
123

124
        wait_operation* next = current->m_next.load(std::memory_order::acquire);
9,747✔
125

126
        if (current == waiter)
9,747✔
127
        {
NEW
128
            if (!m_internal_waiters.compare_exchange_weak(current, next, std::memory_order::acq_rel))
×
NEW
129
                continue;
×
130
        }
131

132
        while (next && next != waiter)
190,246✔
133
        {
134
            current = next;
180,499✔
135
            next    = current->m_next.load(std::memory_order::acquire);
180,499✔
136
        }
137

138
        if (!next)
9,747✔
139
            break;
9,747✔
140

NEW
141
        wait_operation* new_next = waiter->m_next.load(std::memory_order::acquire);
×
142

NEW
143
        if (!current->m_next.compare_exchange_strong(next, new_next, std::memory_order::acq_rel))
×
NEW
144
            continue;
×
145

NEW
146
        waiter->m_next.store(nullptr, std::memory_order::release);
×
NEW
147
        result = true;
×
NEW
148
        break;
×
NEW
149
    }
×
150

151
    return result;
19,910✔
152
}
9,955✔
153

154
condition_variable::wait_operation_guard condition_variable::extract_all()
4✔
155
{
156
    wait_operation_guard result{this};
4✔
157

158
    while (true)
159
    {
160
        auto* current = m_internal_waiters.load(std::memory_order::acquire);
4✔
161
        if (!current)
4✔
NEW
162
            break;
×
163

164
        if (!m_internal_waiters.compare_exchange_weak(current, nullptr, std::memory_order::acq_rel))
4✔
NEW
165
            continue;
×
166

167
        result.set_value(current);
4✔
168
        break;
4✔
NEW
169
    }
×
170

171
    return result;
4✔
172
}
173

174
condition_variable::wait_operation_guard condition_variable::extract_one()
10,002✔
175
{
176
    wait_operation_guard result{this};
10,002✔
177

178
    while (true)
179
    {
180
        auto* current = m_internal_waiters.load(std::memory_order::acquire);
10,029✔
181
        if (!current)
10,029✔
182
            break;
146✔
183

184
        auto* next = current->m_next.load(std::memory_order::acquire);
9,883✔
185
        if (!m_internal_waiters.compare_exchange_weak(current, next, std::memory_order::acq_rel))
9,883✔
186
            continue;
27✔
187

188
        current->m_next.store(nullptr, std::memory_order::release);
9,856✔
189
        result.set_value(current);
9,856✔
190
        break;
9,856✔
191
    }
27✔
192

193
    return result;
10,002✔
194
}
195

196
condition_variable::wait_operation::wait_operation(condition_variable& cv) : m_condition_variable(cv)
9,975✔
197
{
198
}
9,975✔
199

200
condition_variable::wait_operation::~wait_operation()
9,947✔
201
{
202
    m_condition_variable.extract_waiter(this);
9,947✔
203
}
9,955✔
204

205
auto condition_variable::wait_operation::await_suspend(std::coroutine_handle<> awaiting_coroutine) noexcept -> bool
9,975✔
206
{
207
    m_awaiting_coroutine = awaiting_coroutine;
9,975✔
208
    m_condition_variable.insert_waiter(this);
9,975✔
209
    return true;
9,976✔
210
}
211

212
void condition_variable::wait_operation::await_resume() noexcept
9,947✔
213
{
214
}
9,947✔
215

216
condition_variable::cv_lock_guard::cv_lock_guard(condition_variable* cv) noexcept : m_cv(cv)
19,799✔
217
{
218
    m_cv->lock(m_cv);
19,799✔
219
}
19,961✔
220

221
coro::condition_variable::cv_lock_guard::~cv_lock_guard() noexcept
19,961✔
222
{
223
    m_cv->unlock();
19,961✔
224
}
19,961✔
225

226
condition_variable::wait_operation_guard::wait_operation_guard(condition_variable* cv, wait_operation* value) noexcept
10,006✔
227
    : cv_lock_guard(cv),
228
      m_value(value)
10,006✔
229
{
230
}
10,006✔
231

232
condition_variable::wait_operation_guard::operator bool() const noexcept
10,006✔
233
{
234
    return m_value;
10,006✔
235
}
236

237
void condition_variable::wait_operation_guard::set_value(wait_operation* value) noexcept
9,860✔
238
{
239
    m_value = value;
9,860✔
240
}
9,860✔
241

242
condition_variable::wait_operation* condition_variable::wait_operation_guard::value() const noexcept
9,860✔
243
{
244
    return m_value;
9,860✔
245
}
246

247
} // namespace coro
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