#include <folly/ThreadName.h>
#include <folly/io/async/NotificationQueue.h>
+#include <folly/portability/Unistd.h>
#include <condition_variable>
#include <fcntl.h>
#include <mutex>
#include <pthread.h>
-#include <unistd.h>
namespace {
// 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).
- while (!loopKeepAlive_.unique()) {
+ while (loopKeepAliveCount_ > 0) {
applyLoopKeepAlive();
loopOnce();
}
delete &runBeforeLoopCallbacks_.front();
}
- (void) runLoopCallbacks(false);
+ (void)runLoopCallbacks();
if (!fnRunner_->consumeUntilDrained()) {
LOG(ERROR) << "~EventBase(): Unable to drain notification queue";
event_base_free(evb_);
}
- while (!runAfterDrainCallbacks_.empty()) {
- LoopCallback* callback = &runAfterDrainCallbacks_.front();
- runAfterDrainCallbacks_.pop_front();
- callback->runLoopCallback();
- }
-
{
std::lock_guard<std::mutex> lock(localStorageMutex_);
for (auto storage : localStorageToDtor_) {
bool EventBase::loopBody(int flags) {
VLOG(5) << "EventBase(): Starting loop.";
+
+ DCHECK(!invokingLoop_)
+ << "Your code just tried to loop over an event base from inside another "
+ << "event base loop. Since libevent is not reentrant, this leads to "
+ << "undefined behavior in opt builds. Please fix immediately. For the "
+ << "common case of an inner function that needs to do some synchronous "
+ << "computation on an event-base, replace getEventBase() by a new, "
+ << "stack-allocated EvenBase.";
+ invokingLoop_ = true;
+ SCOPE_EXIT {
+ invokingLoop_ = false;
+ };
+
int res = 0;
bool ranLoopCallbacks;
bool blocking = !(flags & EVLOOP_NONBLOCK);
}
void EventBase::applyLoopKeepAlive() {
- if (loopKeepAliveActive_ && loopKeepAlive_.unique()) {
+ if (loopKeepAliveActive_ && loopKeepAliveCount_ == 0) {
// Restore the notification queue internal flag
fnRunner_->stopConsuming();
fnRunner_->startConsumingInternal(this, queue_.get());
loopKeepAliveActive_ = false;
- } else if (!loopKeepAliveActive_ && !loopKeepAlive_.unique()) {
+ } else if (!loopKeepAliveActive_ && loopKeepAliveCount_ > 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.
{
SCOPE_EXIT {
applyLoopKeepAlive();
- loopForeverActive_ = false;
};
- loopForeverActive_ = true;
// Make sure notification queue events are treated as normal events.
- auto loopKeepAlive = loopKeepAlive_;
+ auto keepAlive = loopKeepAlive();
ret = loop();
}
}
}
-void EventBase::runAfterDrain(Func cob) {
- auto callback = new FunctionLoopCallback(std::move(cob));
- std::lock_guard<std::mutex> lg(runAfterDrainCallbacksMutex_);
- callback->cancelLoopCallback();
- runAfterDrainCallbacks_.push_back(*callback);
-}
-
void EventBase::runOnDestruction(LoopCallback* callback) {
std::lock_guard<std::mutex> lg(onDestructionCallbacksMutex_);
callback->cancelLoopCallback();
return true;
}
-bool EventBase::runLoopCallbacks(bool setContext) {
+bool EventBase::runLoopCallbacks() {
if (!loopCallbacks_.empty()) {
bumpHandlingTime();
// Swap the loopCallbacks_ list with a temporary list on our stack.
while (!currentCallbacks.empty()) {
LoopCallback* callback = ¤tCallbacks.front();
currentCallbacks.pop_front();
- if (setContext) {
- RequestContext::setContext(callback->context_);
- }
+ folly::RequestContextScopeGuard rctx(callback->context_);
callback->runLoopCallback();
}