source/async_manual_reset_event.cpp (29 lines of code) (raw):

/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License Version 2.0 with LLVM Exceptions * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://llvm.org/LICENSE.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <unifex/async_manual_reset_event.hpp> namespace unifex::_amre { void async_manual_reset_event::set() noexcept { void* const signalledState = this; // replace the stack of waiting operations with a sentinel indicating we've // been signalled void* top = state_.exchange(signalledState, std::memory_order_acq_rel); if (top == signalledState) { // we were already signalled so there are no waiting operations return; } // We are the first thread to set the state to signalled; iteratively pop // the stack and complete each operation. auto op = static_cast<_op_base*>(top); while (op != nullptr) { std::exchange(op, op->next_)->set_value(); } } void async_manual_reset_event::start_or_wait(_op_base& op, async_manual_reset_event& evt) noexcept { // Try to push op onto the stack of waiting ops. void* const signalledState = &evt; void* top = evt.state_.load(std::memory_order_acquire); do { if (top == signalledState) { // Already in the signalled state; don't push it. op.set_value(); return; } // note: on the first iteration, this line transitions op.next_ from // indeterminate to a well-defined value op.next_ = static_cast<_op_base*>(top); } while (!evt.state_.compare_exchange_weak( top, static_cast<void*>(&op), std::memory_order_release, std::memory_order_acquire)); } } // namespace unfiex::_amre