Add a default timeout parameter to HHWheelTimer.
[folly.git] / folly / experimental / fibers / Baton.h
1 /*
2  * Copyright 2015 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 #pragma once
17
18 #include <atomic>
19
20 #include <folly/detail/Futex.h>
21 #include <folly/experimental/fibers/TimeoutController.h>
22
23 namespace folly { namespace fibers {
24
25 class Fiber;
26
27 /**
28  * @class Baton
29  *
30  * Primitive which allows to put current Fiber to sleep and wake it from another
31  * Fiber/thread.
32  */
33 class Baton {
34  public:
35   Baton();
36
37   ~Baton() {}
38
39   /**
40    * Puts active fiber to sleep. Returns when post is called.
41    */
42   void wait();
43
44   /**
45    * Puts active fiber to sleep. Returns when post is called.
46    *
47    * @param mainContextFunc this function is immediately executed on the main
48    *        context.
49    */
50   template <typename F>
51   void wait(F&& mainContextFunc);
52
53   /**
54    * This is here only not break tao/locks. Please don't use it, because it is
55    * inefficient when used on Fibers.
56    */
57   template<typename C, typename D = typename C::duration>
58   bool timed_wait(const std::chrono::time_point<C,D>& timeout);
59
60   /**
61    * Puts active fiber to sleep. Returns when post is called.
62    *
63    * @param timeout Baton will be automatically awaken if timeout is hit
64    *
65    * @return true if was posted, false if timeout expired
66    */
67   bool timed_wait(TimeoutController::Duration timeout);
68
69   /**
70    * Puts active fiber to sleep. Returns when post is called.
71    *
72    * @param timeout Baton will be automatically awaken if timeout is hit
73    * @param mainContextFunc this function is immediately executed on the main
74    *        context.
75    *
76    * @return true if was posted, false if timeout expired
77    */
78   template <typename F>
79   bool timed_wait(TimeoutController::Duration timeout, F&& mainContextFunc);
80
81   /**
82    * Checks if the baton has been posted without blocking.
83    * @return    true iff the baton has been posted.
84    */
85   bool try_wait();
86
87   /**
88    * Wakes up Fiber which was waiting on this Baton (or if no Fiber is waiting,
89    * next wait() call will return immediately).
90    */
91   void post();
92
93   /**
94    * Reset's the baton (equivalent to destroying the object and constructing
95    * another one in place).
96    * Caller is responsible for making sure no one is waiting on/posting the
97    * baton when reset() is called.
98    */
99   void reset();
100
101  private:
102   enum {
103     /**
104      * Must be positive.  If multiple threads are actively using a
105      * higher-level data structure that uses batons internally, it is
106      * likely that the post() and wait() calls happen almost at the same
107      * time.  In this state, we lose big 50% of the time if the wait goes
108      * to sleep immediately.  On circa-2013 devbox hardware it costs about
109      * 7 usec to FUTEX_WAIT and then be awoken (half the t/iter as the
110      * posix_sem_pingpong test in BatonTests).  We can improve our chances
111      * of early post by spinning for a bit, although we have to balance
112      * this against the loss if we end up sleeping any way.  Spins on this
113      * hw take about 7 nanos (all but 0.5 nanos is the pause instruction).
114      * We give ourself 300 spins, which is about 2 usec of waiting.  As a
115      * partial consolation, since we are using the pause instruction we
116      * are giving a speed boost to the colocated hyperthread.
117      */
118     PreBlockAttempts = 300,
119   };
120
121   explicit Baton(intptr_t state) : waitingFiber_(state) {};
122
123   void postHelper(intptr_t new_value);
124   void postThread();
125   void waitThread();
126
127   template <typename F>
128   inline void waitFiber(FiberManager& fm, F&& mainContextFunc);
129   /**
130    * Spin for "some time" (see discussion on PreBlockAttempts) waiting
131    * for a post.
132    * @return true if we received a post the spin wait, false otherwise. If the
133    *         function returns true then Baton state is guaranteed to be POSTED
134    */
135   bool spinWaitForEarlyPost();
136
137   bool timedWaitThread(TimeoutController::Duration timeout);
138
139   static constexpr intptr_t NO_WAITER = 0;
140   static constexpr intptr_t POSTED = -1;
141   static constexpr intptr_t TIMEOUT = -2;
142   static constexpr intptr_t THREAD_WAITING = -3;
143
144   union {
145     std::atomic<intptr_t> waitingFiber_;
146     struct {
147       folly::detail::Futex<> futex;
148       int32_t _unused_packing;
149     } futex_;
150   };
151 };
152
153 }}
154
155 #include <folly/experimental/fibers/Baton-inl.h>