18#ifdef CONDY_DETAIL_HAS_EXECUTION
33template <
typename T>
class Futex {
39 Futex(std::atomic<T> &futex) : futex_(futex) {}
41 ~Futex() { notify_all_(-EIDRM); }
43 CONDY_DELETE_COPY_MOVE(
Futex);
46 struct [[nodiscard]] WaitSenderImpl;
49#ifdef CONDY_DETAIL_HAS_EXECUTION
50 using WaitSender = detail::StandardSender<WaitSenderImpl>;
52 using WaitSender = WaitSenderImpl;
64 WaitSender
wait(T old)
noexcept {
return {*
this, old}; }
71 WaitFinishHandleBase *handle =
nullptr;
73 std::lock_guard<std::mutex> lock(mutex_);
74 handle = wait_awaiters_.pop_front();
77 handle->set_result(0);
89 class WaitFinishHandleBase;
90 template <
typename Receiver>
class WaitFinishHandle;
92 bool cancel_wait_(WaitFinishHandleBase *handle)
noexcept {
93 std::lock_guard<std::mutex> lock(mutex_);
94 return wait_awaiters_.remove(handle);
97 int32_t request_wait_(WaitFinishHandleBase *handle, T old)
noexcept {
98 std::lock_guard<std::mutex> lock(mutex_);
99 auto val = futex_.load(std::memory_order_relaxed);
103 wait_awaiters_.push_back(handle);
108 void notify_all_(int32_t result)
noexcept {
111 std::lock_guard<std::mutex> lock(mutex_);
112 handles = std::move(wait_awaiters_);
114 while (
auto *handle = handles.pop_front()) {
115 handle->set_result(result);
122 detail::IntrusiveDoubleList<WaitFinishHandleBase,
123 &WaitFinishHandleBase::link_entry_>;
125 mutable std::mutex mutex_;
126 HandleList wait_awaiters_;
127 std::atomic<T> &futex_;
131class Futex<T>::WaitFinishHandleBase :
public detail::WorkInvoker {
133 void schedule() noexcept {
134 assert(runtime_ !=
nullptr);
135 runtime_->schedule_internal(
this);
138 void set_result(int32_t result)
noexcept { result_ = result; }
141 detail::DoubleLinkEntry link_entry_;
144 Runtime *runtime_ =
nullptr;
145 int32_t result_ = -ENOTRECOVERABLE;
149template <
typename Receiver>
150class Futex<T>::WaitFinishHandle
151 :
public detail::InvokerAdapter<WaitFinishHandle<Receiver>,
152 WaitFinishHandleBase> {
154 using Base = detail::InvokerAdapter<WaitFinishHandle, WaitFinishHandleBase>;
156 WaitFinishHandle(
Futex &futex, Receiver receiver)
157 : futex_(futex), receiver_(std::move(receiver)) {}
159 void start(Runtime *runtime, T old)
noexcept {
160 this->runtime_ = runtime;
161 int32_t r = futex_.request_wait_(
this, old);
163 std::move(receiver_)(r);
166 runtime->pend_work_internal();
168 auto stop_token = receiver_.get_stop_token();
169 if (stop_token.stop_possible()) {
170 stop_callback_.emplace(std::move(stop_token), Cancellation{
this});
174 void invoke() noexcept {
175 stop_callback_.reset();
176 assert(this->runtime_ !=
nullptr);
177 this->runtime_->resume_work_internal();
178 std::move(receiver_)(this->result_);
182 void cancel_() noexcept {
183 if (futex_.cancel_wait_(
this)) {
185 this->result_ = -ECANCELED;
186 assert(this->runtime_ !=
nullptr);
187 this->runtime_->schedule_internal(
this);
191 struct Cancellation {
192 WaitFinishHandle *self;
193 void operator()() noexcept { self->cancel_(); }
196 using StopCallbackType =
197 detail::stop_callback_t<detail::stop_token_t<Receiver>, Cancellation>;
202 std::optional<StopCallbackType> stop_callback_;
205template <
typename T>
struct Futex<T>::WaitSenderImpl {
207 using CondySender = void;
208 using ReturnType = int32_t;
210 WaitSenderImpl(
Futex &futex, T old) : futex_(futex), old_(old) {}
212 template <
typename Receiver>
auto connect_impl(Receiver receiver)
noexcept {
213 return OperationState<Receiver>(futex_, old_, std::move(receiver));
217 template <
typename Receiver>
218 class OperationState :
public WaitFinishHandle<Receiver> {
220 using Base = WaitFinishHandle<Receiver>;
221 OperationState(Futex &futex, T old, Receiver receiver)
222 : Base(futex, std::move(receiver)), old_(old) {}
224 void start(
unsigned int )
noexcept {
225 auto *runtime = detail::Context::current().runtime();
226 Base::start(runtime, old_);
User-space "futex" implementation for efficient synchronization between coroutines.
WaitSender wait(T old) noexcept
Wait if the futex value equals to the specified old value. The awaiting coroutine will be suspended u...
Futex(std::atomic< T > &futex)
Construct a new Futex object.
void notify_all() noexcept
Notify all awaiting coroutines.
void notify_one() noexcept
Notify one awaiting coroutine, if any.
Internal sender/receiver adapters for std::execution integration.
Detection and aliasing of the available std::execution backend.
Intrusive single-linked and double-linked list implementations.
Polymorphic invocation utilities.
The main namespace for the Condy library.
Runtime type for running the io_uring event loop.
Internal utility classes and functions used by Condy.