#endif
#include <folly/io/async/EventBase.h>
+#include <folly/io/async/VirtualEventBase.h>
+#include <folly/Memory.h>
#include <folly/ThreadName.h>
#include <folly/io/async/NotificationQueue.h>
#include <folly/portability/Unistd.h>
class EventBase::FunctionRunner
: public NotificationQueue<EventBase::Func>::Consumer {
public:
- void messageAvailable(Func&& msg) override {
+ void messageAvailable(Func&& msg) noexcept override {
// In libevent2, internal events do not break the loop.
// Most users would expect loop(), followed by runInEventBaseThread(),
// to break the loop and check if it should exit or not.
// wake up the loop. We can ignore these messages.
return;
}
-
- // The function should never throw an exception, because we have no
- // way of knowing what sort of error handling to perform.
- //
- // If it does throw, log a message and abort the program.
- try {
- msg();
- } catch (const std::exception& ex) {
- LOG(ERROR) << "runInEventBaseThread() function threw a "
- << typeid(ex).name() << " exception: " << ex.what();
- abort();
- } catch (...) {
- LOG(ERROR) << "runInEventBaseThread() function threw an exception";
- abort();
- }
+ msg();
}
};
}
EventBase::~EventBase() {
+ std::future<void> virtualEventBaseDestroyFuture;
+ if (virtualEventBase_) {
+ virtualEventBaseDestroyFuture = virtualEventBase_->destroy();
+ }
+
// Keep looping until all keep-alive handles are released. Each keep-alive
// handle signals that some external code will still schedule some work on
// this EventBase (so it's not safe to destroy it).
loopOnce();
}
+ if (virtualEventBaseDestroyFuture.valid()) {
+ virtualEventBaseDestroyFuture.get();
+ }
+
// Call all destruction callbacks, before we start cleaning up our state.
while (!onDestructionCallbacks_.empty()) {
LoopCallback* callback = &onDestructionCallbacks_.front();
event_base_free(evb_);
}
- {
- std::lock_guard<std::mutex> lock(localStorageMutex_);
- for (auto storage : localStorageToDtor_) {
- storage->onEventBaseDestruction(*this);
- }
+ for (auto storage : localStorageToDtor_) {
+ storage->onEventBaseDestruction(*this);
}
+
VLOG(5) << "EventBase(): Destroyed.";
}
}
if (enableTimeMeasurement_) {
- VLOG(5) << "EventBase " << this << " loop time: " <<
+ VLOG(11) << "EventBase " << this << " loop time: " <<
getTimeDelta(&prev).count();
}
loopKeepAliveCountAtomic_.exchange(0, std::memory_order_relaxed);
}
DCHECK_GE(loopKeepAliveCount_, 0);
+
return loopKeepAliveCount_;
}
void EventBase::applyLoopKeepAlive() {
- if (loopKeepAliveActive_ && loopKeepAliveCount() == 0) {
+ auto keepAliveCount = loopKeepAliveCount();
+ // Make sure default VirtualEventBase won't hold EventBase::loop() forever.
+ if (virtualEventBase_ && virtualEventBase_->keepAliveCount() == 1) {
+ --keepAliveCount;
+ }
+
+ if (loopKeepAliveActive_ && keepAliveCount == 0) {
// Restore the notification queue internal flag
fnRunner_->stopConsuming();
fnRunner_->startConsumingInternal(this, queue_.get());
loopKeepAliveActive_ = false;
- } else if (!loopKeepAliveActive_ && loopKeepAliveCount() > 0) {
+ } else if (!loopKeepAliveActive_ && keepAliveCount > 0) {
// Update the notification queue event to treat it as a normal
// (non-internal) event. The notification queue event always remains
// installed, and the main loop won't exit with it installed.
const char* EventBase::getLibeventVersion() { return event_get_version(); }
const char* EventBase::getLibeventMethod() { return event_get_method(); }
+VirtualEventBase& EventBase::getVirtualEventBase() {
+ folly::call_once(virtualEventBaseInitFlag_, [&] {
+ virtualEventBase_ = std::make_unique<VirtualEventBase>(*this);
+ });
+
+ return *virtualEventBase_;
+}
+
} // folly