2 * Copyright 2017 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);
70 bool Baton::timed_wait(
71 TimeoutController::Duration 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, std::move(mainContextFunc));
92 auto posted = waitingFiber_ == POSTED;
95 fm->timeoutManager_->cancel(id);
101 template <typename C, typename D>
102 bool Baton::timed_wait(const std::chrono::time_point<C, D>& timeout) {
105 if (LIKELY(now <= timeout)) {
107 std::chrono::duration_cast<std::chrono::milliseconds>(timeout - now));
109 return timed_wait(TimeoutController::Duration(0));