/*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#pragma once
+#include <future>
+
#include <folly/Baton.h>
#include <folly/Executor.h>
#include <folly/io/async/EventBase.h>
*
* Multiple VirtualEventBases can be backed by a single EventBase. Similarly
* to EventBase, VirtualEventBase implements loopKeepAlive() functionality,
- * which allows callbacks holding LoopKeepAlive token to keep EventBase looping
+ * which allows callbacks holding KeepAlive token to keep EventBase looping
* until they are complete.
*
* VirtualEventBase destructor blocks until all its KeepAliveTokens are released
VirtualEventBase(const VirtualEventBase&) = delete;
VirtualEventBase& operator=(const VirtualEventBase&) = delete;
- ~VirtualEventBase();
+ ~VirtualEventBase() override;
EventBase& getEventBase() {
return evb_;
*/
void runOnDestruction(EventBase::LoopCallback* callback);
- /**
- * @see EventBase::runInLoop
- */
- template <typename F>
- void runInLoop(F&& f, bool thisIteration = false) {
- evb_.runInLoop(std::forward<F>(f), thisIteration);
- }
-
/**
* VirtualEventBase destructor blocks until all tasks scheduled through its
* runInEventBaseThread are complete.
*/
template <typename F>
void runInEventBaseThread(F&& f) {
- // LoopKeepAlive token has to be released in the EventBase thread. If
- // runInEventBaseThread() fails, we can't extract the LoopKeepAlive token
+ // KeepAlive token has to be released in the EventBase thread. If
+ // runInEventBaseThread() fails, we can't extract the KeepAlive token
// from the callback to properly release it.
CHECK(evb_.runInEventBaseThread([
- keepAlive = loopKeepAliveAtomic(),
+ keepAliveToken = getKeepAliveToken(),
f = std::forward<F>(f)
]() mutable { f(); }));
}
+ HHWheelTimer& timer() {
+ return evb_.timer();
+ }
+
void attachTimeoutManager(
AsyncTimeout* obj,
TimeoutManager::InternalEnum internal) override {
runInEventBaseThread(std::move(f));
}
- struct LoopKeepAliveDeleter {
- void operator()(VirtualEventBase* evb) {
- DCHECK(evb->getEventBase().inRunningEventBaseThread());
- if (evb->loopKeepAliveCountAtomic_.load()) {
- evb->loopKeepAliveCount_ += evb->loopKeepAliveCountAtomic_.exchange(0);
- }
- DCHECK(evb->loopKeepAliveCount_ > 0);
- if (--evb->loopKeepAliveCount_ == 0) {
- evb->loopKeepAliveBaton_.post();
- }
- }
- };
- using LoopKeepAlive = std::unique_ptr<VirtualEventBase, LoopKeepAliveDeleter>;
-
/**
* Returns you a handle which prevents VirtualEventBase from being destroyed.
- * LoopKeepAlive handle can be released from EventBase loop only.
- *
- * loopKeepAlive() can be called from EventBase thread only.
+ * KeepAlive handle can be released from EventBase loop only.
*/
- LoopKeepAlive loopKeepAlive() {
- DCHECK(evb_.isInEventBaseThread());
- ++loopKeepAliveCount_;
- return LoopKeepAlive(this);
- }
+ KeepAlive getKeepAliveToken() override {
+ DCHECK(loopKeepAliveCount_ + loopKeepAliveCountAtomic_.load() > 0);
- /**
- * Thread-safe version of loopKeepAlive()
- */
- LoopKeepAlive loopKeepAliveAtomic() {
if (evb_.inRunningEventBaseThread()) {
- return loopKeepAlive();
+ ++loopKeepAliveCount_;
+ } else {
+ ++loopKeepAliveCountAtomic_;
}
- ++loopKeepAliveCountAtomic_;
- return LoopKeepAlive(this);
+ return makeKeepAlive();
}
bool inRunningEventBaseThread() const {
return evb_.inRunningEventBaseThread();
}
+ protected:
+ void keepAliveRelease() override {
+ DCHECK(getEventBase().isInEventBaseThread());
+ if (loopKeepAliveCountAtomic_.load()) {
+ loopKeepAliveCount_ += loopKeepAliveCountAtomic_.exchange(0);
+ }
+ DCHECK(loopKeepAliveCount_ > 0);
+ if (--loopKeepAliveCount_ == 0) {
+ destroyImpl();
+ }
+ }
+
private:
+ friend class EventBase;
+
+ ssize_t keepAliveCount() {
+ if (loopKeepAliveCountAtomic_.load()) {
+ loopKeepAliveCount_ += loopKeepAliveCountAtomic_.exchange(0);
+ }
+ return loopKeepAliveCount_;
+ }
+
+ std::future<void> destroy();
+ void destroyImpl();
+
using LoopCallbackList = EventBase::LoopCallback::List;
EventBase& evb_;
- ssize_t loopKeepAliveCount_{0};
+ ssize_t loopKeepAliveCount_{1};
std::atomic<ssize_t> loopKeepAliveCountAtomic_{0};
- folly::Baton<> loopKeepAliveBaton_;
- LoopKeepAlive loopKeepAlive_;
+ std::promise<void> destroyPromise_;
+ std::future<void> destroyFuture_{destroyPromise_.get_future()};
+ KeepAlive loopKeepAlive_{makeKeepAlive()};
- EventBase::LoopKeepAlive evbLoopKeepAlive_;
+ KeepAlive evbLoopKeepAlive_;
folly::Synchronized<LoopCallbackList> onDestructionCallbacks_;
};