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

Avoid external thread event starvation

Summary: Pick some events from the NotificationQueue on every EventBase loop iteration if NotificationQueue is registered as an internal event and there are no other active events.

Reviewed By: yfeldblum

Differential Revision: D13393839

fbshipit-source-id: 9d281ac721db268f321860b1bf55d2afd79f9679
parent 16f20f29
......@@ -378,16 +378,18 @@ bool EventBase::loopBody(int flags, bool ignoreKeepAlive) {
VLOG(11) << "EventBase " << this << " did not timeout";
}
// If the event loop indicate that there were no more events, and
// we also didn't have any loop callbacks to run, there is nothing left to
// do.
if (res != 0 && !ranLoopCallbacks) {
// Event loop indicated that there were no more events (NotificationQueue
// was registered as an internal event and there were no other registered
// events).
if (res != 0) {
// Since Notification Queue is marked 'internal' some events may not have
// run. Run them manually if so, and continue looping.
//
if (getNotificationQueueSize() > 0) {
fnRunner_->handlerReady(0);
} else {
} else if (!ranLoopCallbacks) {
// If there were no more events and we also didn't have any loop
// callbacks to run, there is nothing left to do.
break;
}
}
......
......@@ -27,6 +27,7 @@
#include <folly/futures/Promise.h>
#include <atomic>
#include <future>
#include <iostream>
#include <memory>
#include <thread>
......@@ -2042,3 +2043,36 @@ TEST(EventBaseTest, CancelLoopCallbackRequestContextTest) {
EXPECT_EQ(defaultCtx, RequestContext::get());
}
TEST(EventBaseTest, TestStarvation) {
EventBase evb;
std::promise<void> stopRequested;
std::promise<void> stopScheduled;
bool stopping{false};
std::thread t{[&] {
stopRequested.get_future().get();
evb.add([&]() { stopping = true; });
stopScheduled.set_value();
}};
size_t num{0};
std::function<void()> fn;
fn = [&]() {
if (stopping || num >= 2000) {
return;
}
if (++num == 1000) {
stopRequested.set_value();
stopScheduled.get_future().get();
}
evb.add(fn);
};
evb.add(fn);
evb.loop();
EXPECT_EQ(1000, num);
t.join();
}
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