2 * Copyright 2015 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/experimental/fibers/Fiber.h>
17 #include <folly/experimental/fibers/FiberManager.h>
19 namespace folly { namespace fibers {
21 inline Baton::Baton() : Baton(NO_WAITER) {
22 assert(Baton(NO_WAITER).futex_.futex == static_cast<uint32_t>(NO_WAITER));
23 assert(Baton(POSTED).futex_.futex == static_cast<uint32_t>(POSTED));
24 assert(Baton(TIMEOUT).futex_.futex == static_cast<uint32_t>(TIMEOUT));
25 assert(Baton(THREAD_WAITING).futex_.futex ==
26 static_cast<uint32_t>(THREAD_WAITING));
28 assert(futex_.futex.is_lock_free());
29 assert(waitingFiber_.is_lock_free());
33 void Baton::wait(F&& mainContextFunc) {
34 auto fm = FiberManager::getFiberManagerUnsafe();
35 if (!fm || !fm->activeFiber_) {
40 return waitFiber(*fm, std::forward<F>(mainContextFunc));
44 void Baton::waitFiber(FiberManager& fm, F&& mainContextFunc) {
45 auto& waitingFiber = waitingFiber_;
46 auto f = [&mainContextFunc, &waitingFiber](Fiber& fiber) mutable {
47 auto baton_fiber = waitingFiber.load();
49 if (LIKELY(baton_fiber == NO_WAITER)) {
51 } else if (baton_fiber == POSTED || baton_fiber == TIMEOUT) {
55 throw std::logic_error("Some Fiber is already waiting on this Baton.");
57 } while(!waitingFiber.compare_exchange_weak(
59 reinterpret_cast<intptr_t>(&fiber)));
64 fm.awaitFunc_ = std::ref(f);
65 fm.activeFiber_->preempt(Fiber::AWAITING);
69 bool Baton::timed_wait(TimeoutController::Duration timeout,
70 F&& mainContextFunc) {
71 auto fm = FiberManager::getFiberManagerUnsafe();
73 if (!fm || !fm->activeFiber_) {
75 return timedWaitThread(timeout);
79 bool canceled = false;
80 auto timeoutFunc = [&baton, &canceled]() mutable {
81 baton.postHelper(TIMEOUT);
85 auto id = fm->timeoutManager_->registerTimeout(
86 std::ref(timeoutFunc), timeout);
88 waitFiber(*fm, std::move(mainContextFunc));
90 auto posted = waitingFiber_ == POSTED;
93 fm->timeoutManager_->cancel(id);
99 template<typename C, typename D>
100 bool Baton::timed_wait(const std::chrono::time_point<C,D>& timeout) {
103 if (LIKELY(now <= timeout)) {
105 std::chrono::duration_cast<std::chrono::milliseconds>(timeout - now));
107 return timed_wait(TimeoutController::Duration(0));