2 * Copyright 2017-present Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <folly/fibers/Fiber.h>
17 #include <folly/fibers/FiberManagerInternal.h>
22 inline Baton::Baton() : Baton(NO_WAITER) {
23 assert(Baton(NO_WAITER).futex_.futex == static_cast<uint32_t>(NO_WAITER));
24 assert(Baton(POSTED).futex_.futex == static_cast<uint32_t>(POSTED));
25 assert(Baton(TIMEOUT).futex_.futex == static_cast<uint32_t>(TIMEOUT));
27 Baton(THREAD_WAITING).futex_.futex ==
28 static_cast<uint32_t>(THREAD_WAITING));
30 assert(futex_.futex.is_lock_free());
31 assert(waitingFiber_.is_lock_free());
35 void Baton::wait(F&& mainContextFunc) {
36 auto fm = FiberManager::getFiberManagerUnsafe();
37 if (!fm || !fm->activeFiber_) {
42 return waitFiber(*fm, std::forward<F>(mainContextFunc));
46 void Baton::waitFiber(FiberManager& fm, F&& mainContextFunc) {
47 auto& waitingFiber = waitingFiber_;
48 auto f = [&mainContextFunc, &waitingFiber](Fiber& fiber) mutable {
49 auto baton_fiber = waitingFiber.load();
51 if (LIKELY(baton_fiber == NO_WAITER)) {
53 } else if (baton_fiber == POSTED || baton_fiber == TIMEOUT) {
57 throw std::logic_error("Some Fiber is already waiting on this Baton.");
59 } while (!waitingFiber.compare_exchange_weak(
60 baton_fiber, reinterpret_cast<intptr_t>(&fiber)));
65 fm.awaitFunc_ = std::ref(f);
66 fm.activeFiber_->preempt(Fiber::AWAITING);
69 template <typename Rep, typename Period, typename F>
70 bool Baton::try_wait_for(
71 const std::chrono::duration<Rep, Period>& timeout,
72 F&& mainContextFunc) {
73 auto fm = FiberManager::getFiberManagerUnsafe();
75 if (!fm || !fm->activeFiber_) {
77 return timedWaitThread(timeout);
81 bool canceled = false;
82 auto timeoutFunc = [&baton, &canceled]() mutable {
83 baton.postHelper(TIMEOUT);
88 fm->timeoutManager_->registerTimeout(std::ref(timeoutFunc), timeout);
90 waitFiber(*fm, static_cast<F&&>(mainContextFunc));
92 auto posted = waitingFiber_ == POSTED;
95 fm->timeoutManager_->cancel(id);
101 template <typename Clock, typename Duration, typename F>
102 bool Baton::try_wait_until(
103 const std::chrono::time_point<Clock, Duration>& deadline,
104 F&& mainContextFunc) {
105 auto now = Clock::now();
107 if (LIKELY(now <= deadline)) {
108 return try_wait_for(deadline - now, static_cast<F&&>(mainContextFunc));
110 return try_wait_for(Duration{}, static_cast<F&&>(mainContextFunc));
113 } // namespace fibers