Commit ab60aed9 authored by Andrii Grynenko's avatar Andrii Grynenko Committed by Facebook Github Bot

Move runAfterDelay/tryRunAfterDelay into TimeoutManager

Summary: This is useful to add more TimeoutManager implementations.

Reviewed By: yfeldblum

Differential Revision: D4164236

fbshipit-source-id: 5f2057f6ebfbdc971bc0b5594e3bc4b5a337aaef
parent 8c88eb0a
...@@ -447,6 +447,7 @@ libfolly_la_SOURCES = \ ...@@ -447,6 +447,7 @@ libfolly_la_SOURCES = \
io/async/SSLContext.cpp \ io/async/SSLContext.cpp \
io/async/ScopedEventBaseThread.cpp \ io/async/ScopedEventBaseThread.cpp \
io/async/HHWheelTimer.cpp \ io/async/HHWheelTimer.cpp \
io/async/TimeoutManager.cpp \
io/async/test/ScopedBoundPort.cpp \ io/async/test/ScopedBoundPort.cpp \
io/async/test/SocketPair.cpp \ io/async/test/SocketPair.cpp \
io/async/test/TimeUtil.cpp \ io/async/test/TimeUtil.cpp \
......
...@@ -89,28 +89,6 @@ class EventBase::FunctionRunner ...@@ -89,28 +89,6 @@ class EventBase::FunctionRunner
} }
}; };
/*
* EventBase::CobTimeout methods
*/
void EventBase::CobTimeout::timeoutExpired() noexcept {
// For now, we just swallow any exceptions that the callback threw.
try {
cob_();
} catch (const std::exception& ex) {
LOG(ERROR) << "EventBase::runAfterDelay() callback threw "
<< typeid(ex).name() << " exception: " << ex.what();
} catch (...) {
LOG(ERROR) << "EventBase::runAfterDelay() callback threw non-exception "
<< "type";
}
// The CobTimeout object was allocated on the heap by runAfterDelay(),
// so delete it now that the it has fired.
delete this;
}
// The interface used to libevent is not thread-safe. Calls to // The interface used to libevent is not thread-safe. Calls to
// event_init() and event_base_free() directly modify an internal // event_init() and event_base_free() directly modify an internal
// global 'current_base', so a mutex is required to protect this. // global 'current_base', so a mutex is required to protect this.
...@@ -210,14 +188,7 @@ EventBase::~EventBase() { ...@@ -210,14 +188,7 @@ EventBase::~EventBase() {
callback->runLoopCallback(); callback->runLoopCallback();
} }
// Delete any unfired callback objects, so that we don't leak memory clearCobTimeouts();
// (Note that we don't fire them. The caller is responsible for cleaning up
// its own data structures if it destroys the EventBase with unfired events
// remaining.)
while (!pendingCobTimeouts_.empty()) {
CobTimeout* timeout = &pendingCobTimeouts_.front();
delete timeout;
}
while (!runBeforeLoopCallbacks_.empty()) { while (!runBeforeLoopCallbacks_.empty()) {
delete &runBeforeLoopCallbacks_.front(); delete &runBeforeLoopCallbacks_.front();
...@@ -620,29 +591,6 @@ bool EventBase::runImmediatelyOrRunInEventBaseThreadAndWait(Func fn) { ...@@ -620,29 +591,6 @@ bool EventBase::runImmediatelyOrRunInEventBaseThreadAndWait(Func fn) {
} }
} }
void EventBase::runAfterDelay(
Func cob,
uint32_t milliseconds,
TimeoutManager::InternalEnum in) {
if (!tryRunAfterDelay(std::move(cob), milliseconds, in)) {
folly::throwSystemError(
"error in EventBase::runAfterDelay(), failed to schedule timeout");
}
}
bool EventBase::tryRunAfterDelay(
Func cob,
uint32_t milliseconds,
TimeoutManager::InternalEnum in) {
CobTimeout* timeout = new CobTimeout(this, std::move(cob), in);
if (!timeout->scheduleTimeout(milliseconds)) {
delete timeout;
return false;
}
pendingCobTimeouts_.push_back(*timeout);
return true;
}
bool EventBase::runLoopCallbacks() { bool EventBase::runLoopCallbacks() {
if (!loopCallbacks_.empty()) { if (!loopCallbacks_.empty()) {
bumpHandlingTime(); bumpHandlingTime();
......
...@@ -397,28 +397,6 @@ class EventBase : private boost::noncopyable, ...@@ -397,28 +397,6 @@ class EventBase : private boost::noncopyable,
*/ */
bool runImmediatelyOrRunInEventBaseThreadAndWait(Func fn); bool runImmediatelyOrRunInEventBaseThreadAndWait(Func fn);
/**
* Runs the given Cob at some time after the specified number of
* milliseconds. (No guarantees exactly when.)
*
* Throws a std::system_error if an error occurs.
*/
void runAfterDelay(
Func c,
uint32_t milliseconds,
TimeoutManager::InternalEnum in = TimeoutManager::InternalEnum::NORMAL);
/**
* @see tryRunAfterDelay for more details
*
* @return true iff the cob was successfully registered.
*
* */
bool tryRunAfterDelay(
Func cob,
uint32_t milliseconds,
TimeoutManager::InternalEnum in = TimeoutManager::InternalEnum::NORMAL);
/** /**
* Set the maximum desired latency in us and provide a callback which will be * Set the maximum desired latency in us and provide a callback which will be
* called when that latency is exceeded. * called when that latency is exceeded.
...@@ -430,7 +408,6 @@ class EventBase : private boost::noncopyable, ...@@ -430,7 +408,6 @@ class EventBase : private boost::noncopyable,
maxLatencyCob_ = std::move(maxLatencyCob); maxLatencyCob_ = std::move(maxLatencyCob);
} }
/** /**
* Set smoothing coefficient for loop load average; # of milliseconds * Set smoothing coefficient for loop load average; # of milliseconds
* for exp(-1) (1/2.71828...) decay. * for exp(-1) (1/2.71828...) decay.
...@@ -602,22 +579,23 @@ class EventBase : private boost::noncopyable, ...@@ -602,22 +579,23 @@ class EventBase : private boost::noncopyable,
return LoopKeepAlive(this); return LoopKeepAlive(this);
} }
private:
// TimeoutManager // TimeoutManager
void attachTimeoutManager(AsyncTimeout* obj, void attachTimeoutManager(
TimeoutManager::InternalEnum internal) override; AsyncTimeout* obj,
TimeoutManager::InternalEnum internal) override final;
void detachTimeoutManager(AsyncTimeout* obj) override; void detachTimeoutManager(AsyncTimeout* obj) override final;
bool scheduleTimeout(AsyncTimeout* obj, TimeoutManager::timeout_type timeout) bool scheduleTimeout(AsyncTimeout* obj, TimeoutManager::timeout_type timeout)
override; override final;
void cancelTimeout(AsyncTimeout* obj) override; void cancelTimeout(AsyncTimeout* obj) override final;
bool isInTimeoutManagerThread() override final { bool isInTimeoutManagerThread() override final {
return isInEventBaseThread(); return isInEventBaseThread();
} }
private:
void applyLoopKeepAlive(); void applyLoopKeepAlive();
/* /*
...@@ -626,30 +604,6 @@ class EventBase : private boost::noncopyable, ...@@ -626,30 +604,6 @@ class EventBase : private boost::noncopyable,
*/ */
bool nothingHandledYet() const noexcept; bool nothingHandledYet() const noexcept;
// small object used as a callback arg with enough info to execute the
// appropriate client-provided Cob
class CobTimeout : public AsyncTimeout {
public:
CobTimeout(EventBase* b, Func c, TimeoutManager::InternalEnum in)
: AsyncTimeout(b, in), cob_(std::move(c)) {}
virtual void timeoutExpired() noexcept;
private:
Func cob_;
public:
typedef boost::intrusive::list_member_hook<
boost::intrusive::link_mode<boost::intrusive::auto_unlink> > ListHook;
ListHook hook;
typedef boost::intrusive::list<
CobTimeout,
boost::intrusive::member_hook<CobTimeout, ListHook, &CobTimeout::hook>,
boost::intrusive::constant_time_size<false> > List;
};
typedef LoopCallback::List LoopCallbackList; typedef LoopCallback::List LoopCallbackList;
class FunctionRunner; class FunctionRunner;
...@@ -663,8 +617,6 @@ class EventBase : private boost::noncopyable, ...@@ -663,8 +617,6 @@ class EventBase : private boost::noncopyable,
// should only be accessed through public getter // should only be accessed through public getter
HHWheelTimer::UniquePtr wheelTimer_; HHWheelTimer::UniquePtr wheelTimer_;
CobTimeout::List pendingCobTimeouts_;
LoopCallbackList loopCallbacks_; LoopCallbackList loopCallbacks_;
LoopCallbackList runBeforeLoopCallbacks_; LoopCallbackList runBeforeLoopCallbacks_;
LoopCallbackList onDestructionCallbacks_; LoopCallbackList onDestructionCallbacks_;
......
/*
* Copyright 2016 Facebook, Inc.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <folly/io/async/TimeoutManager.h>
#include <boost/intrusive/list.hpp>
#include <folly/Exception.h>
#include <folly/io/async/AsyncTimeout.h>
#include <glog/logging.h>
namespace folly {
struct TimeoutManager::CobTimeouts {
// small object used as a callback arg with enough info to execute the
// appropriate client-provided Cob
class CobTimeout : public AsyncTimeout {
public:
CobTimeout(TimeoutManager* timeoutManager, Func cob, InternalEnum internal)
: AsyncTimeout(timeoutManager, internal), cob_(std::move(cob)) {}
void timeoutExpired() noexcept override {
// For now, we just swallow any exceptions that the callback threw.
try {
cob_();
} catch (const std::exception& ex) {
LOG(ERROR) << "TimeoutManager::runAfterDelay() callback threw "
<< typeid(ex).name() << " exception: " << ex.what();
} catch (...) {
LOG(ERROR) << "TimeoutManager::runAfterDelay() callback threw "
<< "non-exception type";
}
// The CobTimeout object was allocated on the heap by runAfterDelay(),
// so delete it now that the it has fired.
delete this;
}
private:
Func cob_;
public:
using ListHook = boost::intrusive::list_member_hook<
boost::intrusive::link_mode<boost::intrusive::auto_unlink>>;
ListHook hook;
using List = boost::intrusive::list<
CobTimeout,
boost::intrusive::member_hook<CobTimeout, ListHook, &CobTimeout::hook>,
boost::intrusive::constant_time_size<false>>;
};
CobTimeout::List list;
};
TimeoutManager::TimeoutManager()
: cobTimeouts_(std::make_unique<CobTimeouts>()) {}
void TimeoutManager::runAfterDelay(
Func cob,
uint32_t milliseconds,
InternalEnum internal) {
if (!tryRunAfterDelay(std::move(cob), milliseconds, internal)) {
folly::throwSystemError(
"error in TimeoutManager::runAfterDelay(), failed to schedule timeout");
}
}
bool TimeoutManager::tryRunAfterDelay(
Func cob,
uint32_t milliseconds,
InternalEnum internal) {
if (!cobTimeouts_) {
return false;
}
auto timeout =
std::make_unique<CobTimeouts::CobTimeout>(this, std::move(cob), internal);
if (!timeout->scheduleTimeout(milliseconds)) {
return false;
}
cobTimeouts_->list.push_back(*timeout.release());
return true;
}
void TimeoutManager::clearCobTimeouts() {
if (!cobTimeouts_) {
return;
}
// Delete any unfired callback objects, so that we don't leak memory
// Note that we don't fire them.
while (!cobTimeouts_->list.empty()) {
auto* timeout = &cobTimeouts_->list.front();
delete timeout;
}
}
TimeoutManager::~TimeoutManager() {
clearCobTimeouts();
}
}
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include <chrono> #include <chrono>
#include <stdint.h> #include <stdint.h>
#include <folly/Function.h>
namespace folly { namespace folly {
class AsyncTimeout; class AsyncTimeout;
...@@ -35,13 +37,16 @@ class AsyncTimeout; ...@@ -35,13 +37,16 @@ class AsyncTimeout;
class TimeoutManager { class TimeoutManager {
public: public:
typedef std::chrono::milliseconds timeout_type; typedef std::chrono::milliseconds timeout_type;
using Func = folly::Function<void()>;
enum class InternalEnum { enum class InternalEnum {
INTERNAL, INTERNAL,
NORMAL NORMAL
}; };
virtual ~TimeoutManager() = default; TimeoutManager();
virtual ~TimeoutManager();
/** /**
* Attaches/detaches TimeoutManager to AsyncTimeout * Attaches/detaches TimeoutManager to AsyncTimeout
...@@ -72,6 +77,34 @@ class TimeoutManager { ...@@ -72,6 +77,34 @@ class TimeoutManager {
* thread * thread
*/ */
virtual bool isInTimeoutManagerThread() = 0; virtual bool isInTimeoutManagerThread() = 0;
/**
* Runs the given Cob at some time after the specified number of
* milliseconds. (No guarantees exactly when.)
*
* Throws a std::system_error if an error occurs.
*/
void runAfterDelay(
Func cob,
uint32_t milliseconds,
InternalEnum internal = InternalEnum::NORMAL);
/**
* @see tryRunAfterDelay for more details
*
* @return true iff the cob was successfully registered.
*/
bool tryRunAfterDelay(
Func cob,
uint32_t milliseconds,
InternalEnum internal = InternalEnum::NORMAL);
protected:
void clearCobTimeouts();
private:
struct CobTimeouts;
std::unique_ptr<CobTimeouts> cobTimeouts_;
}; };
} // folly } // folly
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment