diff options
-rw-r--r-- | simpleperf/IOEventLoop.cpp | 32 | ||||
-rw-r--r-- | simpleperf/IOEventLoop.h | 24 | ||||
-rw-r--r-- | simpleperf/IOEventLoop_test.cpp | 42 | ||||
-rw-r--r-- | simpleperf/cmd_monitor.cpp | 9 | ||||
-rw-r--r-- | simpleperf/cmd_record.cpp | 11 |
5 files changed, 92 insertions, 26 deletions
diff --git a/simpleperf/IOEventLoop.cpp b/simpleperf/IOEventLoop.cpp index 06bdd713..239fff97 100644 --- a/simpleperf/IOEventLoop.cpp +++ b/simpleperf/IOEventLoop.cpp @@ -84,6 +84,10 @@ bool IOEventLoop::EnsureInit() { return false; } event_config_free(cfg); + if (event_base_priority_init(ebase_, 2) != 0) { + LOG(ERROR) << "event_base_priority_init failed"; + return false; + } } if (ebase_ == nullptr) { LOG(ERROR) << "failed to create event_base"; @@ -110,39 +114,44 @@ static bool MakeFdNonBlocking(int fd) { return true; } -IOEventRef IOEventLoop::AddReadEvent(int fd, const std::function<bool()>& callback) { +IOEventRef IOEventLoop::AddReadEvent(int fd, const std::function<bool()>& callback, + IOEventPriority priority) { if (!MakeFdNonBlocking(fd)) { return nullptr; } - return AddEvent(fd, EV_READ | EV_PERSIST, nullptr, callback); + return AddEvent(fd, EV_READ | EV_PERSIST, nullptr, callback, priority); } -IOEventRef IOEventLoop::AddWriteEvent(int fd, const std::function<bool()>& callback) { +IOEventRef IOEventLoop::AddWriteEvent(int fd, const std::function<bool()>& callback, + IOEventPriority priority) { if (!MakeFdNonBlocking(fd)) { return nullptr; } - return AddEvent(fd, EV_WRITE | EV_PERSIST, nullptr, callback); + return AddEvent(fd, EV_WRITE | EV_PERSIST, nullptr, callback, priority); } -bool IOEventLoop::AddSignalEvent(int sig, const std::function<bool()>& callback) { - return AddEvent(sig, EV_SIGNAL | EV_PERSIST, nullptr, callback) != nullptr; +bool IOEventLoop::AddSignalEvent(int sig, const std::function<bool()>& callback, + IOEventPriority priority) { + return AddEvent(sig, EV_SIGNAL | EV_PERSIST, nullptr, callback, priority) != nullptr; } -bool IOEventLoop::AddSignalEvents(std::vector<int> sigs, const std::function<bool()>& callback) { +bool IOEventLoop::AddSignalEvents(std::vector<int> sigs, const std::function<bool()>& callback, + IOEventPriority priority) { for (auto sig : sigs) { - if (!AddSignalEvent(sig, callback)) { + if (!AddSignalEvent(sig, callback, priority)) { return false; } } return true; } -IOEventRef IOEventLoop::AddPeriodicEvent(timeval duration, const std::function<bool()>& callback) { - return AddEvent(-1, EV_PERSIST, &duration, callback); +IOEventRef IOEventLoop::AddPeriodicEvent(timeval duration, const std::function<bool()>& callback, + IOEventPriority priority) { + return AddEvent(-1, EV_PERSIST, &duration, callback, priority); } IOEventRef IOEventLoop::AddEvent(int fd_or_sig, int16_t events, timeval* timeout, - const std::function<bool()>& callback) { + const std::function<bool()>& callback, IOEventPriority priority) { if (!EnsureInit()) { return nullptr; } @@ -152,6 +161,7 @@ IOEventRef IOEventLoop::AddEvent(int fd_or_sig, int16_t events, timeval* timeout LOG(ERROR) << "event_new() failed"; return nullptr; } + event_priority_set(e->e, priority); if (event_add(e->e, timeout) != 0) { LOG(ERROR) << "event_add() failed"; return nullptr; diff --git a/simpleperf/IOEventLoop.h b/simpleperf/IOEventLoop.h index 0bbbbd01..1578a4d0 100644 --- a/simpleperf/IOEventLoop.h +++ b/simpleperf/IOEventLoop.h @@ -32,6 +32,12 @@ namespace simpleperf { struct IOEvent; typedef IOEvent* IOEventRef; +enum IOEventPriority { + // Lower value means higher priority. + IOEventHighPriority = 0, + IOEventLowPriority = 1, +}; + // IOEventLoop is a class wrapper of libevent, it monitors events happened, // and calls the corresponding callbacks. Possible events are: file ready to // read, file ready to write, signal happens, periodic timer timeout. @@ -46,22 +52,27 @@ class IOEventLoop { // Register a read Event, so [callback] is called when [fd] can be read // without blocking. If registered successfully, return the reference // to control the Event, otherwise return nullptr. - IOEventRef AddReadEvent(int fd, const std::function<bool()>& callback); + IOEventRef AddReadEvent(int fd, const std::function<bool()>& callback, + IOEventPriority priority = IOEventLowPriority); // Register a write Event, so [callback] is called when [fd] can be written // without blocking. - IOEventRef AddWriteEvent(int fd, const std::function<bool()>& callback); + IOEventRef AddWriteEvent(int fd, const std::function<bool()>& callback, + IOEventPriority priority = IOEventLowPriority); // Register a signal Event, so [callback] is called each time signal [sig] // happens. - bool AddSignalEvent(int sig, const std::function<bool()>& callback); + bool AddSignalEvent(int sig, const std::function<bool()>& callback, + IOEventPriority priority = IOEventLowPriority); // Register a vector of signal Events. - bool AddSignalEvents(std::vector<int> sigs, const std::function<bool()>& callback); + bool AddSignalEvents(std::vector<int> sigs, const std::function<bool()>& callback, + IOEventPriority priority = IOEventLowPriority); // Register a periodic Event, so [callback] is called periodically every // [duration]. - IOEventRef AddPeriodicEvent(timeval duration, const std::function<bool()>& callback); + IOEventRef AddPeriodicEvent(timeval duration, const std::function<bool()>& callback, + IOEventPriority priority = IOEventLowPriority); // Run a loop polling for Events. It only exits when ExitLoop() is called // in a callback function of registered Events. @@ -81,7 +92,8 @@ class IOEventLoop { private: bool EnsureInit(); IOEventRef AddEvent(int fd_or_sig, int16_t events, timeval* timeout, - const std::function<bool()>& callback); + const std::function<bool()>& callback, + IOEventPriority priority = IOEventLowPriority); static void EventCallbackFn(int, int16_t, void*); event_base* ebase_; diff --git a/simpleperf/IOEventLoop_test.cpp b/simpleperf/IOEventLoop_test.cpp index 09f64522..658fe820 100644 --- a/simpleperf/IOEventLoop_test.cpp +++ b/simpleperf/IOEventLoop_test.cpp @@ -250,3 +250,45 @@ TEST(IOEventLoop, exit_before_loop) { IOEventLoop loop; ASSERT_TRUE(loop.ExitLoop()); } + +TEST(IOEventLoop, priority) { + int low_priority_fd[2]; + ASSERT_EQ(0, pipe(low_priority_fd)); + int high_priority_fd[2]; + ASSERT_EQ(0, pipe(high_priority_fd)); + + IOEventLoop loop; + int count = 0; + + ASSERT_NE(nullptr, loop.AddReadEvent( + low_priority_fd[0], + [&]() { + char c; + read(low_priority_fd[0], &c, 1); + CHECK_EQ(count, 1); + count++; + return loop.ExitLoop(); + }, + IOEventLowPriority)); + + ASSERT_NE(nullptr, loop.AddReadEvent( + high_priority_fd[0], + [&]() { + char c; + read(high_priority_fd[0], &c, 1); + CHECK_EQ(count, 0); + count++; + return true; + }, + IOEventHighPriority)); + + char c; + CHECK_EQ(write(low_priority_fd[1], &c, 1), 1); + CHECK_EQ(write(high_priority_fd[1], &c, 1), 1); + ASSERT_TRUE(loop.RunLoop()); + ASSERT_EQ(2, count); + for (int i = 0; i < 2; i++) { + close(low_priority_fd[i]); + close(high_priority_fd[i]); + } +} diff --git a/simpleperf/cmd_monitor.cpp b/simpleperf/cmd_monitor.cpp index 355f9d51..d81ccfea 100644 --- a/simpleperf/cmd_monitor.cpp +++ b/simpleperf/cmd_monitor.cpp @@ -266,21 +266,22 @@ bool MonitorCommand::PrepareMonitoring() { // 5. Add read/signal/periodic Events. IOEventLoop* loop = event_selection_set_.GetIOEventLoop(); auto exit_loop_callback = [loop]() { return loop->ExitLoop(); }; - if (!loop->AddSignalEvents({SIGCHLD, SIGINT, SIGTERM}, exit_loop_callback)) { + if (!loop->AddSignalEvents({SIGCHLD, SIGINT, SIGTERM}, exit_loop_callback, IOEventHighPriority)) { return false; } // Only add an event for SIGHUP if we didn't inherit SIG_IGN (e.g. from // nohup). if (!SignalIsIgnored(SIGHUP)) { - if (!loop->AddSignalEvent(SIGHUP, exit_loop_callback)) { + if (!loop->AddSignalEvent(SIGHUP, exit_loop_callback, IOEventHighPriority)) { return false; } } if (duration_in_sec_ != 0) { - if (!loop->AddPeriodicEvent(SecondToTimeval(duration_in_sec_), - [loop]() { return loop->ExitLoop(); })) { + if (!loop->AddPeriodicEvent( + SecondToTimeval(duration_in_sec_), [loop]() { return loop->ExitLoop(); }, + IOEventHighPriority)) { return false; } } diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp index 1c53dc1c..35cab822 100644 --- a/simpleperf/cmd_record.cpp +++ b/simpleperf/cmd_record.cpp @@ -629,25 +629,26 @@ bool RecordCommand::PrepareRecording(Workload* workload) { } IOEventLoop* loop = event_selection_set_.GetIOEventLoop(); auto exit_loop_callback = [loop]() { return loop->ExitLoop(); }; - if (!loop->AddSignalEvents({SIGCHLD, SIGINT, SIGTERM}, exit_loop_callback)) { + if (!loop->AddSignalEvents({SIGCHLD, SIGINT, SIGTERM}, exit_loop_callback, IOEventHighPriority)) { return false; } // Only add an event for SIGHUP if we didn't inherit SIG_IGN (e.g. from nohup). if (!SignalIsIgnored(SIGHUP)) { - if (!loop->AddSignalEvent(SIGHUP, exit_loop_callback)) { + if (!loop->AddSignalEvent(SIGHUP, exit_loop_callback, IOEventHighPriority)) { return false; } } if (stop_signal_fd_ != -1) { - if (!loop->AddReadEvent(stop_signal_fd_, exit_loop_callback)) { + if (!loop->AddReadEvent(stop_signal_fd_, exit_loop_callback, IOEventHighPriority)) { return false; } } if (duration_in_sec_ != 0) { - if (!loop->AddPeriodicEvent(SecondToTimeval(duration_in_sec_), - [loop]() { return loop->ExitLoop(); })) { + if (!loop->AddPeriodicEvent( + SecondToTimeval(duration_in_sec_), [loop]() { return loop->ExitLoop(); }, + IOEventHighPriority)) { return false; } } |