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 <boost/capy/ex/frame_allocator.hpp>
12  
#include <condition_variable>
13  
#include <condition_variable>
13  
#include <mutex>
14  
#include <mutex>
14  
#include <queue>
15  
#include <queue>
15  

16  

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

20  

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

29  

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

34  

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

39  

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

45  

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

53  

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

63  

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

85  

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

96  

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

98  

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

105  

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

111  

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

116  

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

121  

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

128  

128  
void
129  
void
129  
blocking_executor::post(
130  
blocking_executor::post(
130  
    continuation& c) const
131  
    continuation& c) const
131  
{
132  
{
132  
    ctx_->enqueue(c.h);
133  
    ctx_->enqueue(c.h);
133  
}
134  
}
134  

135  

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