Make EPoll actually return from Run even if you call Quit repeatedly
This comes up for integrating external event loops.
Change-Id: Icf8c9cbb7ee0c9ac5d677ab0445a8966d94f2708
Signed-off-by: Austin Schuh <austin.schuh@bluerivertech.com>
diff --git a/aos/events/epoll.cc b/aos/events/epoll.cc
index 1c4427b..7fff6ef 100644
--- a/aos/events/epoll.cc
+++ b/aos/events/epoll.cc
@@ -127,7 +127,14 @@
return true;
}
-void EPoll::Quit() { PCHECK(write(quit_signal_fd_, "q", 1) == 1); }
+void EPoll::Quit() {
+ // Shortcut to break us out of infinite loops. We might write more than once
+ // to the pipe, but we'll stop once the first is read on the other end.
+ if (!run_) {
+ return;
+ }
+ PCHECK(write(quit_signal_fd_, "q", 1) == 1);
+}
void EPoll::OnReadable(int fd, ::std::function<void()> function) {
EventData *event_data = GetEventData(fd);
diff --git a/aos/events/epoll_test.cc b/aos/events/epoll_test.cc
index 66460c2..053a09b 100644
--- a/aos/events/epoll_test.cc
+++ b/aos/events/epoll_test.cc
@@ -3,8 +3,8 @@
#include <fcntl.h>
#include <unistd.h>
-#include "gtest/gtest.h"
#include "glog/logging.h"
+#include "gtest/gtest.h"
namespace aos {
namespace internal {
@@ -48,22 +48,22 @@
};
class EPollTest : public ::testing::Test {
- public:
- void RunFor(std::chrono::nanoseconds duration) {
- TimerFd timerfd;
- bool did_quit = false;
- epoll_.OnReadable(timerfd.fd(), [this, &timerfd, &did_quit]() {
- CHECK(!did_quit);
- epoll_.Quit();
- did_quit = true;
- timerfd.Read();
- });
- timerfd.SetTime(monotonic_clock::now() + duration,
- monotonic_clock::duration::zero());
- epoll_.Run();
- CHECK(did_quit);
- epoll_.DeleteFd(timerfd.fd());
- }
+ public:
+ void RunFor(std::chrono::nanoseconds duration) {
+ TimerFd timerfd;
+ bool did_quit = false;
+ epoll_.OnReadable(timerfd.fd(), [this, &timerfd, &did_quit]() {
+ CHECK(!did_quit);
+ epoll_.Quit();
+ did_quit = true;
+ timerfd.Read();
+ });
+ timerfd.SetTime(monotonic_clock::now() + duration,
+ monotonic_clock::duration::zero());
+ epoll_.Run();
+ CHECK(did_quit);
+ epoll_.DeleteFd(timerfd.fd());
+ }
// Tests should avoid relying on ordering for events closer in time than this,
// or waiting for longer than this to ensure events happen in order.
@@ -71,7 +71,7 @@
return std::chrono::milliseconds(50);
}
- EPoll epoll_;
+ EPoll epoll_;
};
// Test that the basics of OnReadable work.
@@ -201,6 +201,11 @@
epoll_.DeleteFd(pipe.write_fd());
}
+TEST_F(EPollTest, QuitInBeforeWait) {
+ epoll_.BeforeWait([this]() { epoll_.Quit(); });
+ epoll_.Run();
+}
+
} // namespace testing
} // namespace internal
} // namespace aos