io/async/SSLContext.cpp \
io/async/ScopedEventBaseThread.cpp \
io/async/HHWheelTimer.cpp \
+ io/async/TimeoutManager.cpp \
io/async/test/ScopedBoundPort.cpp \
io/async/test/SocketPair.cpp \
io/async/test/TimeUtil.cpp \
}
};
-/*
- * 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
// event_init() and event_base_free() directly modify an internal
// global 'current_base', so a mutex is required to protect this.
callback->runLoopCallback();
}
- // Delete any unfired callback objects, so that we don't leak memory
- // (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;
- }
+ clearCobTimeouts();
while (!runBeforeLoopCallbacks_.empty()) {
delete &runBeforeLoopCallbacks_.front();
}
}
-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() {
if (!loopCallbacks_.empty()) {
bumpHandlingTime();
*/
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
* called when that latency is exceeded.
maxLatencyCob_ = std::move(maxLatencyCob);
}
-
/**
* Set smoothing coefficient for loop load average; # of milliseconds
* for exp(-1) (1/2.71828...) decay.
return LoopKeepAlive(this);
}
- private:
// TimeoutManager
- void attachTimeoutManager(AsyncTimeout* obj,
- TimeoutManager::InternalEnum internal) override;
+ void attachTimeoutManager(
+ 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)
- override;
+ override final;
- void cancelTimeout(AsyncTimeout* obj) override;
+ void cancelTimeout(AsyncTimeout* obj) override final;
bool isInTimeoutManagerThread() override final {
return isInEventBaseThread();
}
+ private:
void applyLoopKeepAlive();
/*
*/
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;
class FunctionRunner;
// should only be accessed through public getter
HHWheelTimer::UniquePtr wheelTimer_;
- CobTimeout::List pendingCobTimeouts_;
-
LoopCallbackList loopCallbacks_;
LoopCallbackList runBeforeLoopCallbacks_;
LoopCallbackList onDestructionCallbacks_;
--- /dev/null
+/*
+ * 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/Memory.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_(folly::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 = folly::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();
+}
+}
#include <chrono>
#include <stdint.h>
+#include <folly/Function.h>
+
namespace folly {
class AsyncTimeout;
class TimeoutManager {
public:
typedef std::chrono::milliseconds timeout_type;
+ using Func = folly::Function<void()>;
enum class InternalEnum {
INTERNAL,
NORMAL
};
- virtual ~TimeoutManager() = default;
+ TimeoutManager();
+
+ virtual ~TimeoutManager();
/**
* Attaches/detaches TimeoutManager to AsyncTimeout
* thread
*/
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