86e91cf09c1bf9c951d37cf3c14746e7e7cea9db
[folly.git] / folly / io / async / AsyncTimeout.h
1 /*
2  * Copyright 2014 Facebook, Inc.
3  *
4  * Licensed to the Apache Software Foundation (ASF) under one
5  * or more contributor license agreements. See the NOTICE file
6  * distributed with this work for additional information
7  * regarding copyright ownership. The ASF licenses this file
8  * to you under the Apache License, Version 2.0 (the
9  * "License"); you may not use this file except in compliance
10  * with the License. You may obtain a copy of the License at
11  *
12  *   http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  * KIND, either express or implied. See the License for the
18  * specific language governing permissions and limitations
19  * under the License.
20  */
21 #pragma once
22
23 #include <folly/io/async/TimeoutManager.h>
24
25 #include <boost/noncopyable.hpp>
26 #include <event.h>
27 #include <memory>
28
29 namespace folly {
30
31 class EventBase;
32 class RequestContext;
33 class TimeoutManager;
34
35 /**
36  * AsyncTimeout is used to asynchronously wait for a timeout to occur.
37  */
38 class AsyncTimeout : private boost::noncopyable {
39  public:
40   typedef TimeoutManager::InternalEnum InternalEnum;
41
42   /**
43    * Create a new AsyncTimeout object, driven by the specified TimeoutManager.
44    */
45   explicit AsyncTimeout(TimeoutManager* timeoutManager);
46   explicit AsyncTimeout(EventBase* eventBase);
47
48   /**
49    * Create a new internal AsyncTimeout object.
50    *
51    * Internal timeouts are like regular timeouts, but will not stop the
52    * TimeoutManager loop from exiting if the only remaining events are internal
53    * timeouts.
54    *
55    * This is useful for implementing fallback timeouts to abort the
56    * TimeoutManager loop if the other events have not been processed within a
57    * specified time period: if the event loop takes too long the timeout will
58    * fire and can stop the event loop.  However, if all other events complete,
59    * the event loop will exit even though the internal timeout is still
60    * installed.
61    */
62   AsyncTimeout(TimeoutManager* timeoutManager, InternalEnum internal);
63   AsyncTimeout(EventBase* eventBase, InternalEnum internal);
64
65   /**
66    * Create a new AsyncTimeout object, not yet assigned to a TimeoutManager.
67    *
68    * attachEventBase() must be called prior to scheduling the timeout.
69    */
70   AsyncTimeout();
71
72   /**
73    * AsyncTimeout destructor.
74    *
75    * The timeout will be automatically cancelled if it is running.
76    */
77   virtual ~AsyncTimeout();
78
79   /**
80    * timeoutExpired() is invoked when the timeout period has expired.
81    */
82   virtual void timeoutExpired() noexcept = 0;
83
84   /**
85    * Schedule the timeout to fire in the specified number of milliseconds.
86    *
87    * After the specified number of milliseconds has elapsed, timeoutExpired()
88    * will be invoked by the TimeoutManager's main loop.
89    *
90    * If the timeout is already running, it will be rescheduled with the
91    * new timeout value.
92    *
93    * @param milliseconds  The timeout duration, in milliseconds.
94    *
95    * @return Returns true if the timeout was successfully scheduled,
96    *         and false if an error occurred.  After an error, the timeout is
97    *         always unscheduled, even if scheduleTimeout() was just
98    *         rescheduling an existing timeout.
99    */
100   bool scheduleTimeout(uint32_t milliseconds);
101   bool scheduleTimeout(std::chrono::milliseconds timeout);
102
103   /**
104    * Cancel the timeout, if it is running.
105    */
106   void cancelTimeout();
107
108   /**
109    * Returns true if the timeout is currently scheduled.
110    */
111   bool isScheduled() const;
112
113   /**
114    * Attach the timeout to a TimeoutManager.
115    *
116    * This may only be called if the timeout is not currently attached to a
117    * TimeoutManager (either by using the default constructor, or by calling
118    * detachTimeoutManager()).
119    *
120    * This method must be invoked in the TimeoutManager's thread.
121    *
122    * The internal parameter specifies if this timeout should be treated as an
123    * internal event.  TimeoutManager::loop() will return when there are no more
124    * non-internal events remaining.
125    */
126   void attachTimeoutManager(TimeoutManager* timeoutManager,
127                             InternalEnum internal = InternalEnum::NORMAL);
128   void attachEventBase(EventBase* eventBase,
129                        InternalEnum internal = InternalEnum::NORMAL);
130
131   /**
132    * Detach the timeout from its TimeoutManager.
133    *
134    * This may only be called when the timeout is not running.
135    * Once detached, the timeout may not be scheduled again until it is
136    * re-attached to a EventBase by calling attachEventBase().
137    *
138    * This method must be called from the current TimeoutManager's thread.
139    */
140   void detachTimeoutManager();
141   void detachEventBase();
142
143   const TimeoutManager* getTimeoutManager() {
144     return timeoutManager_;
145   }
146
147   /**
148    * Returns the internal handle to the event
149    */
150   struct event* getEvent() {
151     return &event_;
152   }
153
154  private:
155   static void libeventCallback(int fd, short events, void* arg);
156
157   struct event event_;
158
159   /*
160    * Store a pointer to the TimeoutManager.  We only use this
161    * for some assert() statements, to make sure that AsyncTimeout is always
162    * used from the correct thread.
163    */
164   TimeoutManager* timeoutManager_;
165
166   // Save the request context for when the timeout fires.
167   std::shared_ptr<RequestContext> context_;
168 };
169
170 } // folly