2 * Copyright 2017 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
21 #include <folly/io/async/TimeoutManager.h>
23 #include <boost/intrusive/list.hpp>
25 #include <folly/Exception.h>
26 #include <folly/Memory.h>
27 #include <folly/io/async/AsyncTimeout.h>
29 #include <glog/logging.h>
33 struct TimeoutManager::CobTimeouts {
34 // small object used as a callback arg with enough info to execute the
35 // appropriate client-provided Cob
36 class CobTimeout : public AsyncTimeout {
38 CobTimeout(TimeoutManager* timeoutManager, Func cob, InternalEnum internal)
39 : AsyncTimeout(timeoutManager, internal), cob_(std::move(cob)) {}
41 void timeoutExpired() noexcept override {
42 // For now, we just swallow any exceptions that the callback threw.
45 } catch (const std::exception& ex) {
46 LOG(ERROR) << "TimeoutManager::runAfterDelay() callback threw "
47 << typeid(ex).name() << " exception: " << ex.what();
49 LOG(ERROR) << "TimeoutManager::runAfterDelay() callback threw "
50 << "non-exception type";
53 // The CobTimeout object was allocated on the heap by runAfterDelay(),
54 // so delete it now that the it has fired.
62 using ListHook = boost::intrusive::list_member_hook<
63 boost::intrusive::link_mode<boost::intrusive::auto_unlink>>;
65 using List = boost::intrusive::list<
67 boost::intrusive::member_hook<CobTimeout, ListHook, &CobTimeout::hook>,
68 boost::intrusive::constant_time_size<false>>;
71 CobTimeout::List list;
74 TimeoutManager::TimeoutManager()
75 : cobTimeouts_(folly::make_unique<CobTimeouts>()) {}
77 void TimeoutManager::runAfterDelay(
79 uint32_t milliseconds,
80 InternalEnum internal) {
81 if (!tryRunAfterDelay(std::move(cob), milliseconds, internal)) {
82 folly::throwSystemError(
83 "error in TimeoutManager::runAfterDelay(), failed to schedule timeout");
87 bool TimeoutManager::tryRunAfterDelay(
89 uint32_t milliseconds,
90 InternalEnum internal) {
95 auto timeout = folly::make_unique<CobTimeouts::CobTimeout>(
96 this, std::move(cob), internal);
97 if (!timeout->scheduleTimeout(milliseconds)) {
100 cobTimeouts_->list.push_back(*timeout.release());
104 void TimeoutManager::clearCobTimeouts() {
109 // Delete any unfired callback objects, so that we don't leak memory
110 // Note that we don't fire them.
111 while (!cobTimeouts_->list.empty()) {
112 auto* timeout = &cobTimeouts_->list.front();
117 TimeoutManager::~TimeoutManager() {