2 * Copyright 2016 Facebook, Inc.
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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
23 #include <folly/io/async/TimeoutManager.h>
25 #include <boost/noncopyable.hpp>
37 * AsyncTimeout is used to asynchronously wait for a timeout to occur.
39 class AsyncTimeout : private boost::noncopyable {
41 typedef TimeoutManager::InternalEnum InternalEnum;
44 * Create a new AsyncTimeout object, driven by the specified TimeoutManager.
46 explicit AsyncTimeout(TimeoutManager* timeoutManager);
47 explicit AsyncTimeout(EventBase* eventBase);
50 * Create a new internal AsyncTimeout object.
52 * Internal timeouts are like regular timeouts, but will not stop the
53 * TimeoutManager loop from exiting if the only remaining events are internal
56 * This is useful for implementing fallback timeouts to abort the
57 * TimeoutManager loop if the other events have not been processed within a
58 * specified time period: if the event loop takes too long the timeout will
59 * fire and can stop the event loop. However, if all other events complete,
60 * the event loop will exit even though the internal timeout is still
63 AsyncTimeout(TimeoutManager* timeoutManager, InternalEnum internal);
64 AsyncTimeout(EventBase* eventBase, InternalEnum internal);
67 * Create a new AsyncTimeout object, not yet assigned to a TimeoutManager.
69 * attachEventBase() must be called prior to scheduling the timeout.
74 * AsyncTimeout destructor.
76 * The timeout will be automatically cancelled if it is running.
78 virtual ~AsyncTimeout();
81 * timeoutExpired() is invoked when the timeout period has expired.
83 virtual void timeoutExpired() noexcept = 0;
86 * Schedule the timeout to fire in the specified number of milliseconds.
88 * After the specified number of milliseconds has elapsed, timeoutExpired()
89 * will be invoked by the TimeoutManager's main loop.
91 * If the timeout is already running, it will be rescheduled with the
94 * @param milliseconds The timeout duration, in milliseconds.
96 * @return Returns true if the timeout was successfully scheduled,
97 * and false if an error occurred. After an error, the timeout is
98 * always unscheduled, even if scheduleTimeout() was just
99 * rescheduling an existing timeout.
101 bool scheduleTimeout(uint32_t milliseconds);
102 bool scheduleTimeout(TimeoutManager::timeout_type timeout);
105 * Cancel the timeout, if it is running.
107 void cancelTimeout();
110 * Returns true if the timeout is currently scheduled.
112 bool isScheduled() const;
115 * Attach the timeout to a TimeoutManager.
117 * This may only be called if the timeout is not currently attached to a
118 * TimeoutManager (either by using the default constructor, or by calling
119 * detachTimeoutManager()).
121 * This method must be invoked in the TimeoutManager's thread.
123 * The internal parameter specifies if this timeout should be treated as an
124 * internal event. TimeoutManager::loop() will return when there are no more
125 * non-internal events remaining.
127 void attachTimeoutManager(TimeoutManager* timeoutManager,
128 InternalEnum internal = InternalEnum::NORMAL);
129 void attachEventBase(EventBase* eventBase,
130 InternalEnum internal = InternalEnum::NORMAL);
133 * Detach the timeout from its TimeoutManager.
135 * This may only be called when the timeout is not running.
136 * Once detached, the timeout may not be scheduled again until it is
137 * re-attached to a EventBase by calling attachEventBase().
139 * This method must be called from the current TimeoutManager's thread.
141 void detachTimeoutManager();
142 void detachEventBase();
144 const TimeoutManager* getTimeoutManager() {
145 return timeoutManager_;
149 * Returns the internal handle to the event
151 struct event* getEvent() {
156 * Convenience function that wraps a function object as
157 * an AsyncTimeout instance and returns the wrapper.
159 * Specially useful when using lambdas as AsyncTimeout
164 * void foo(TimeoutManager &manager) {
165 * std::atomic_bool done = false;
167 * auto observer = AsyncTimeout::make(manager, [&] {
168 * std::cout << "hello, world!" << std::endl;
172 * observer->scheduleTimeout(std::chrono::seconds(5));
174 * while (!done); // busy wait
177 * @author: Marcelo Juchem <marcelo@fb.com>
179 template <typename TCallback>
180 static std::unique_ptr<AsyncTimeout> make(
181 TimeoutManager &manager,
186 * Convenience function that wraps a function object as
187 * an AsyncTimeout instance and returns the wrapper
188 * after scheduling it using the given TimeoutManager.
190 * This is equivalent to calling `make_async_timeout`
191 * followed by a `scheduleTimeout` on the resulting
194 * Specially useful when using lambdas as AsyncTimeout
199 * void foo(TimeoutManager &manager) {
200 * std::atomic_bool done = false;
202 * auto observer = AsyncTimeout::schedule(
203 * std::chrono::seconds(5), manager, [&] {
204 * std::cout << "hello, world!" << std::endl;
209 * while (!done); // busy wait
212 * @author: Marcelo Juchem <marcelo@fb.com>
214 template <typename TCallback>
215 static std::unique_ptr<AsyncTimeout> schedule(
216 TimeoutManager::timeout_type timeout,
217 TimeoutManager &manager,
222 static void libeventCallback(int fd, short events, void* arg);
227 * Store a pointer to the TimeoutManager. We only use this
228 * for some assert() statements, to make sure that AsyncTimeout is always
229 * used from the correct thread.
231 TimeoutManager* timeoutManager_;
233 // Save the request context for when the timeout fires.
234 std::shared_ptr<RequestContext> context_;
240 * Wraps a function object as an AsyncTimeout instance.
242 * @author: Marcelo Juchem <marcelo@fb.com>
244 template <typename TCallback>
245 struct async_timeout_wrapper:
248 template <typename UCallback>
249 async_timeout_wrapper(TimeoutManager *manager, UCallback &&callback):
250 AsyncTimeout(manager),
251 callback_(std::forward<UCallback>(callback))
254 void timeoutExpired() noexcept {
256 noexcept(std::declval<TCallback>()()),
257 "callback must be declared noexcept, e.g.: `[]() noexcept {}`"
266 } // namespace detail {
268 template <typename TCallback>
269 std::unique_ptr<AsyncTimeout> AsyncTimeout::make(
270 TimeoutManager &manager,
273 return std::unique_ptr<AsyncTimeout>(
274 new detail::async_timeout_wrapper<typename std::decay<TCallback>::type>(
275 std::addressof(manager),
276 std::forward<TCallback>(callback)
281 template <typename TCallback>
282 std::unique_ptr<AsyncTimeout> AsyncTimeout::schedule(
283 TimeoutManager::timeout_type timeout,
284 TimeoutManager &manager,
287 auto wrapper = AsyncTimeout::make(manager, std::forward<TCallback>(callback));
288 wrapper->scheduleTimeout(timeout);