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.
20 #include <folly/detail/Futex.h>
21 #include <folly/fibers/TimeoutController.h>
32 * Primitive which allows one to put current Fiber to sleep and wake it from
33 * another Fiber/thread.
44 * Puts active fiber to sleep. Returns when post is called.
49 * Put active fiber to sleep indefinitely. However, timeoutHandler may
50 * be used elsewhere on the same thread in order to schedule a wakeup
51 * for the active fiber. Users of timeoutHandler must be on the same thread
52 * as the active fiber and may only schedule one timeout, which must occur
53 * after the active fiber calls wait.
55 void wait(TimeoutHandler& timeoutHandler);
58 * Puts active fiber to sleep. Returns when post is called.
60 * @param mainContextFunc this function is immediately executed on the main
64 void wait(F&& mainContextFunc);
67 * This is here only not break tao/locks. Please don't use it, because it is
68 * inefficient when used on Fibers.
70 template <typename C, typename D = typename C::duration>
71 bool timed_wait(const std::chrono::time_point<C, D>& timeout);
74 * Puts active fiber to sleep. Returns when post is called.
76 * @param timeout Baton will be automatically awaken if timeout is hit
78 * @return true if was posted, false if timeout expired
80 bool timed_wait(TimeoutController::Duration timeout);
83 * Puts active fiber to sleep. Returns when post is called.
85 * @param timeout Baton will be automatically awaken if timeout is hit
86 * @param mainContextFunc this function is immediately executed on the main
89 * @return true if was posted, false if timeout expired
92 bool timed_wait(TimeoutController::Duration timeout, F&& mainContextFunc);
95 * Checks if the baton has been posted without blocking.
96 * @return true iff the baton has been posted.
101 * Wakes up Fiber which was waiting on this Baton (or if no Fiber is waiting,
102 * next wait() call will return immediately).
107 * Reset's the baton (equivalent to destroying the object and constructing
108 * another one in place).
109 * Caller is responsible for making sure no one is waiting on/posting the
110 * baton when reset() is called.
115 * Provides a way to schedule a wakeup for a wait()ing fiber.
116 * A TimeoutHandler must be passed to Baton::wait(TimeoutHandler&)
117 * before a timeout is scheduled. It is only safe to use the
118 * TimeoutHandler on the same thread as the wait()ing fiber.
119 * scheduleTimeout() may only be called once prior to the end of the
120 * associated Baton's life.
122 class TimeoutHandler {
124 void scheduleTimeout(TimeoutController::Duration timeoutMs);
129 void cancelTimeout();
131 std::function<void()> timeoutFunc_{nullptr};
132 FiberManager* fiberManager_{nullptr};
134 intptr_t timeoutPtr_{0};
140 * Must be positive. If multiple threads are actively using a
141 * higher-level data structure that uses batons internally, it is
142 * likely that the post() and wait() calls happen almost at the same
143 * time. In this state, we lose big 50% of the time if the wait goes
144 * to sleep immediately. On circa-2013 devbox hardware it costs about
145 * 7 usec to FUTEX_WAIT and then be awoken (half the t/iter as the
146 * posix_sem_pingpong test in BatonTests). We can improve our chances
147 * of early post by spinning for a bit, although we have to balance
148 * this against the loss if we end up sleeping any way. Spins on this
149 * hw take about 7 nanos (all but 0.5 nanos is the pause instruction).
150 * We give ourself 300 spins, which is about 2 usec of waiting. As a
151 * partial consolation, since we are using the pause instruction we
152 * are giving a speed boost to the colocated hyperthread.
154 PreBlockAttempts = 300,
157 explicit Baton(intptr_t state) : waitingFiber_(state) {}
159 void postHelper(intptr_t new_value);
163 template <typename F>
164 inline void waitFiber(FiberManager& fm, F&& mainContextFunc);
166 * Spin for "some time" (see discussion on PreBlockAttempts) waiting
168 * @return true if we received a post the spin wait, false otherwise. If the
169 * function returns true then Baton state is guaranteed to be POSTED
171 bool spinWaitForEarlyPost();
173 bool timedWaitThread(TimeoutController::Duration timeout);
175 static constexpr intptr_t NO_WAITER = 0;
176 static constexpr intptr_t POSTED = -1;
177 static constexpr intptr_t TIMEOUT = -2;
178 static constexpr intptr_t THREAD_WAITING = -3;
181 std::atomic<intptr_t> waitingFiber_;
183 folly::detail::Futex<> futex;
184 int32_t _unused_packing;
188 } // namespace fibers
191 #include <folly/fibers/Baton-inl.h>