2 * Copyright 2004-present 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.
17 #include <folly/io/async/TimeoutManager.h>
19 #include <boost/intrusive/list.hpp>
21 #include <folly/Exception.h>
22 #include <folly/Memory.h>
23 #include <folly/io/async/AsyncTimeout.h>
25 #include <glog/logging.h>
29 struct TimeoutManager::CobTimeouts {
30 // small object used as a callback arg with enough info to execute the
31 // appropriate client-provided Cob
32 class CobTimeout : public AsyncTimeout {
34 CobTimeout(TimeoutManager* timeoutManager, Func cob, InternalEnum internal)
35 : AsyncTimeout(timeoutManager, internal), cob_(std::move(cob)) {}
37 void timeoutExpired() noexcept override {
38 // For now, we just swallow any exceptions that the callback threw.
41 } catch (const std::exception& ex) {
42 LOG(ERROR) << "TimeoutManager::runAfterDelay() callback threw "
43 << typeid(ex).name() << " exception: " << ex.what();
45 LOG(ERROR) << "TimeoutManager::runAfterDelay() callback threw "
46 << "non-exception type";
49 // The CobTimeout object was allocated on the heap by runAfterDelay(),
50 // so delete it now that the it has fired.
58 using ListHook = boost::intrusive::list_member_hook<
59 boost::intrusive::link_mode<boost::intrusive::auto_unlink>>;
61 using List = boost::intrusive::list<
63 boost::intrusive::member_hook<CobTimeout, ListHook, &CobTimeout::hook>,
64 boost::intrusive::constant_time_size<false>>;
67 CobTimeout::List list;
70 TimeoutManager::TimeoutManager()
71 : cobTimeouts_(std::make_unique<CobTimeouts>()) {}
73 void TimeoutManager::runAfterDelay(
75 uint32_t milliseconds,
76 InternalEnum internal) {
77 if (!tryRunAfterDelay(std::move(cob), milliseconds, internal)) {
78 folly::throwSystemError(
79 "error in TimeoutManager::runAfterDelay(), failed to schedule timeout");
83 bool TimeoutManager::tryRunAfterDelay(
85 uint32_t milliseconds,
86 InternalEnum internal) {
92 std::make_unique<CobTimeouts::CobTimeout>(this, std::move(cob), internal);
93 if (!timeout->scheduleTimeout(milliseconds)) {
96 cobTimeouts_->list.push_back(*timeout.release());
100 void TimeoutManager::clearCobTimeouts() {
105 // Delete any unfired callback objects, so that we don't leak memory
106 // Note that we don't fire them.
107 while (!cobTimeouts_->list.empty()) {
108 auto* timeout = &cobTimeouts_->list.front();
113 TimeoutManager::~TimeoutManager() {