1  
//
1  
//
2  
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/cppalliance/capy
7  
// Official repository: https://github.com/cppalliance/capy
8  
//
8  
//
9  

9  

10  
#include <boost/capy/test/run_blocking.hpp>
10  
#include <boost/capy/test/run_blocking.hpp>
11  

11  

12  
#include <condition_variable>
12  
#include <condition_variable>
13  
#include <mutex>
13  
#include <mutex>
14  
#include <queue>
14  
#include <queue>
15  

15  

16  
namespace boost {
16  
namespace boost {
17  
namespace capy {
17  
namespace capy {
18  
namespace test {
18  
namespace test {
19  

19  

20  
struct blocking_context::impl
20  
struct blocking_context::impl
21  
{
21  
{
22  
    std::mutex mtx;
22  
    std::mutex mtx;
23  
    std::condition_variable cv;
23  
    std::condition_variable cv;
24  
    std::queue<std::coroutine_handle<>> queue;
24  
    std::queue<std::coroutine_handle<>> queue;
25  
    std::exception_ptr ep;
25  
    std::exception_ptr ep;
26  
    bool done = false;
26  
    bool done = false;
27  
};
27  
};
28  

28  

29  
blocking_context::blocking_context()
29  
blocking_context::blocking_context()
30  
    : impl_(new impl)
30  
    : impl_(new impl)
31  
{
31  
{
32  
}
32  
}
33  

33  

34  
blocking_context::~blocking_context()
34  
blocking_context::~blocking_context()
35  
{
35  
{
36  
    delete impl_;
36  
    delete impl_;
37  
}
37  
}
38  

38  

39  
blocking_executor
39  
blocking_executor
40  
blocking_context::get_executor() noexcept
40  
blocking_context::get_executor() noexcept
41  
{
41  
{
42  
    return blocking_executor{this};
42  
    return blocking_executor{this};
43  
}
43  
}
44  

44  

45  
void
45  
void
46  
blocking_context::signal_done() noexcept
46  
blocking_context::signal_done() noexcept
47  
{
47  
{
48  
    std::lock_guard<std::mutex> lock(impl_->mtx);
48  
    std::lock_guard<std::mutex> lock(impl_->mtx);
49  
    impl_->done = true;
49  
    impl_->done = true;
50  
    impl_->cv.notify_one();
50  
    impl_->cv.notify_one();
51  
}
51  
}
52  

52  

53  
void
53  
void
54  
blocking_context::signal_done(
54  
blocking_context::signal_done(
55  
    std::exception_ptr ep) noexcept
55  
    std::exception_ptr ep) noexcept
56  
{
56  
{
57  
    std::lock_guard<std::mutex> lock(impl_->mtx);
57  
    std::lock_guard<std::mutex> lock(impl_->mtx);
58  
    impl_->ep = ep;
58  
    impl_->ep = ep;
59  
    impl_->done = true;
59  
    impl_->done = true;
60  
    impl_->cv.notify_one();
60  
    impl_->cv.notify_one();
61  
}
61  
}
62  

62  

63  
void
63  
void
64  
blocking_context::run()
64  
blocking_context::run()
65  
{
65  
{
66  
    for(;;)
66  
    for(;;)
67  
    {
67  
    {
68  
        std::coroutine_handle<> h;
68  
        std::coroutine_handle<> h;
69  
        {
69  
        {
70  
            std::unique_lock<std::mutex> lock(impl_->mtx);
70  
            std::unique_lock<std::mutex> lock(impl_->mtx);
71  
            impl_->cv.wait(lock, [&] {
71  
            impl_->cv.wait(lock, [&] {
72  
                return impl_->done || !impl_->queue.empty();
72  
                return impl_->done || !impl_->queue.empty();
73  
            });
73  
            });
74  
            if(impl_->done && impl_->queue.empty())
74  
            if(impl_->done && impl_->queue.empty())
75  
                break;
75  
                break;
76  
            h = impl_->queue.front();
76  
            h = impl_->queue.front();
77  
            impl_->queue.pop();
77  
            impl_->queue.pop();
78  
        }
78  
        }
79  
        h.resume();
79  
        h.resume();
80  
    }
80  
    }
81  
    if(impl_->ep)
81  
    if(impl_->ep)
82  
        std::rethrow_exception(impl_->ep);
82  
        std::rethrow_exception(impl_->ep);
83  
}
83  
}
84  

84  

85  
void
85  
void
86  
blocking_context::enqueue(
86  
blocking_context::enqueue(
87  
    std::coroutine_handle<> h)
87  
    std::coroutine_handle<> h)
88  
{
88  
{
89  
    {
89  
    {
90  
        std::lock_guard<std::mutex> lock(impl_->mtx);
90  
        std::lock_guard<std::mutex> lock(impl_->mtx);
91  
        impl_->queue.push(h);
91  
        impl_->queue.push(h);
92  
    }
92  
    }
93  
    impl_->cv.notify_one();
93  
    impl_->cv.notify_one();
94  
}
94  
}
95  

95  

96  
//----------------------------------------------------------
96  
//----------------------------------------------------------
97  

97  

98  
bool
98  
bool
99  
blocking_executor::operator==(
99  
blocking_executor::operator==(
100  
    blocking_executor const& other) const noexcept
100  
    blocking_executor const& other) const noexcept
101  
{
101  
{
102  
    return ctx_ == other.ctx_;
102  
    return ctx_ == other.ctx_;
103  
}
103  
}
104  

104  

105  
blocking_context&
105  
blocking_context&
106  
blocking_executor::context() const noexcept
106  
blocking_executor::context() const noexcept
107  
{
107  
{
108  
    return *ctx_;
108  
    return *ctx_;
109  
}
109  
}
110  

110  

111  
void
111  
void
112  
blocking_executor::on_work_started() const noexcept
112  
blocking_executor::on_work_started() const noexcept
113  
{
113  
{
114  
}
114  
}
115  

115  

116  
void
116  
void
117  
blocking_executor::on_work_finished() const noexcept
117  
blocking_executor::on_work_finished() const noexcept
118  
{
118  
{
119  
}
119  
}
120  

120  

121  
std::coroutine_handle<>
121  
std::coroutine_handle<>
122  
blocking_executor::dispatch(
122  
blocking_executor::dispatch(
123  
    std::coroutine_handle<> h) const
123  
    std::coroutine_handle<> h) const
124  
{
124  
{
125  
    return h;
125  
    return h;
126  
}
126  
}
127  

127  

128  
void
128  
void
129  
blocking_executor::post(
129  
blocking_executor::post(
130  
    std::coroutine_handle<> h) const
130  
    std::coroutine_handle<> h) const
131  
{
131  
{
132  
    ctx_->enqueue(h);
132  
    ctx_->enqueue(h);
133  
}
133  
}
134  

134  

135  
} // namespace test
135  
} // namespace test
136  
} // namespace capy
136  
} // namespace capy
137  
} // namespace boost
137  
} // namespace boost