1 | /* |
2 | * Copyright 2018-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #include <folly/Portability.h> |
18 | |
19 | #if FOLLY_HAS_COROUTINES |
20 | |
21 | #include <folly/experimental/coro/Baton.h> |
22 | |
23 | #include <cassert> |
24 | |
25 | using namespace folly::coro; |
26 | |
27 | Baton::~Baton() { |
28 | // Should not be any waiting coroutines when the baton is destruced. |
29 | // Caller should ensure the baton is posted before destructing. |
30 | assert( |
31 | state_.load(std::memory_order_relaxed) == static_cast<void*>(this) || |
32 | state_.load(std::memory_order_relaxed) == nullptr); |
33 | } |
34 | |
35 | void Baton::post() noexcept { |
36 | void* signalledState = static_cast<void*>(this); |
37 | void* oldValue = state_.exchange(signalledState, std::memory_order_acq_rel); |
38 | if (oldValue != signalledState && oldValue != nullptr) { |
39 | // We are the first thread to set the state to signalled and there is |
40 | // a waiting coroutine. We are responsible for resuming it. |
41 | WaitOperation* awaiter = static_cast<WaitOperation*>(oldValue); |
42 | awaiter->awaitingCoroutine_.resume(); |
43 | } |
44 | } |
45 | |
46 | bool Baton::waitImpl(WaitOperation* awaiter) const noexcept { |
47 | void* oldValue = nullptr; |
48 | if (!state_.compare_exchange_strong( |
49 | oldValue, |
50 | static_cast<void*>(awaiter), |
51 | std::memory_order_release, |
52 | std::memory_order_acquire)) { |
53 | // If the compare-exchange fails it should be because the baton was |
54 | // set to the signalled state. If this not the case then this could |
55 | // indicate that there are two awaiting coroutines. |
56 | assert(oldValue == static_cast<const void*>(this)); |
57 | return false; |
58 | } |
59 | return true; |
60 | } |
61 | |
62 | #endif // FOLLY_HAS_COROUTINES |
63 | |