Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 : //
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)
6 : //
7 : // Official repository: https://github.com/cppalliance/capy
8 : //
9 :
10 : #include <boost/capy/test/run_blocking.hpp>
11 :
12 : #include <condition_variable>
13 : #include <mutex>
14 : #include <queue>
15 :
16 : namespace boost {
17 : namespace capy {
18 : namespace test {
19 :
20 : struct blocking_context::impl
21 : {
22 : std::mutex mtx;
23 : std::condition_variable cv;
24 : std::queue<std::coroutine_handle<>> queue;
25 : std::exception_ptr ep;
26 : bool done = false;
27 : };
28 :
29 1876 : blocking_context::blocking_context()
30 1876 : : impl_(new impl)
31 : {
32 1876 : }
33 :
34 1876 : blocking_context::~blocking_context()
35 : {
36 1876 : delete impl_;
37 1876 : }
38 :
39 : blocking_executor
40 1876 : blocking_context::get_executor() noexcept
41 : {
42 1876 : return blocking_executor{this};
43 : }
44 :
45 : void
46 1176 : blocking_context::signal_done() noexcept
47 : {
48 1176 : std::lock_guard<std::mutex> lock(impl_->mtx);
49 1176 : impl_->done = true;
50 1176 : impl_->cv.notify_one();
51 1176 : }
52 :
53 : void
54 692 : blocking_context::signal_done(
55 : std::exception_ptr ep) noexcept
56 : {
57 692 : std::lock_guard<std::mutex> lock(impl_->mtx);
58 692 : impl_->ep = ep;
59 692 : impl_->done = true;
60 692 : impl_->cv.notify_one();
61 692 : }
62 :
63 : void
64 1868 : blocking_context::run()
65 : {
66 : for(;;)
67 : {
68 1868 : std::coroutine_handle<> h;
69 : {
70 1868 : std::unique_lock<std::mutex> lock(impl_->mtx);
71 1868 : impl_->cv.wait(lock, [&] {
72 1868 : return impl_->done || !impl_->queue.empty();
73 : });
74 1868 : if(impl_->done && impl_->queue.empty())
75 1868 : break;
76 0 : h = impl_->queue.front();
77 0 : impl_->queue.pop();
78 1868 : }
79 0 : h.resume();
80 0 : }
81 1868 : if(impl_->ep)
82 692 : std::rethrow_exception(impl_->ep);
83 1176 : }
84 :
85 : void
86 0 : blocking_context::enqueue(
87 : std::coroutine_handle<> h)
88 : {
89 : {
90 0 : std::lock_guard<std::mutex> lock(impl_->mtx);
91 0 : impl_->queue.push(h);
92 0 : }
93 0 : impl_->cv.notify_one();
94 0 : }
95 :
96 : //----------------------------------------------------------
97 :
98 : bool
99 0 : blocking_executor::operator==(
100 : blocking_executor const& other) const noexcept
101 : {
102 0 : return ctx_ == other.ctx_;
103 : }
104 :
105 : blocking_context&
106 1868 : blocking_executor::context() const noexcept
107 : {
108 1868 : return *ctx_;
109 : }
110 :
111 : void
112 1868 : blocking_executor::on_work_started() const noexcept
113 : {
114 1868 : }
115 :
116 : void
117 1868 : blocking_executor::on_work_finished() const noexcept
118 : {
119 1868 : }
120 :
121 : std::coroutine_handle<>
122 1868 : blocking_executor::dispatch(
123 : std::coroutine_handle<> h) const
124 : {
125 1868 : return h;
126 : }
127 :
128 : void
129 0 : blocking_executor::post(
130 : std::coroutine_handle<> h) const
131 : {
132 0 : ctx_->enqueue(h);
133 0 : }
134 :
135 : } // namespace test
136 : } // namespace capy
137 : } // namespace boost
|