Add TimerHandler to event loop
Change-Id: I85c9142bcff9bf2cc5b8d003d24b8d77567fbe4a
diff --git a/aos/events/shm-event-loop.cc b/aos/events/shm-event-loop.cc
index d227a48..832b27b 100644
--- a/aos/events/shm-event-loop.cc
+++ b/aos/events/shm-event-loop.cc
@@ -1,6 +1,8 @@
#include "aos/events/shm-event-loop.h"
+#include "aos/common/logging/logging.h"
#include "aos/common/queue.h"
+#include <sys/timerfd.h>
#include <atomic>
#include <chrono>
#include <stdexcept>
@@ -91,7 +93,7 @@
}
{
- MutexLocker locker2(&thread_state_->mutex_);
+ MutexLocker locker(&thread_state_->mutex_);
if (!thread_state_->is_running()) break;
watcher_(reinterpret_cast<const Message *>(msg));
@@ -110,6 +112,61 @@
RawQueue *queue_;
std::function<void(const Message *message)> watcher_;
};
+
+class TimerHandlerState : public TimerHandler {
+ public:
+ TimerHandlerState(std::shared_ptr<ShmEventLoop::ThreadState> thread_state,
+ ::std::function<void()> fn)
+ : thread_state_(std::move(thread_state)), fn_(::std::move(fn)) {
+ fd_ = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
+ PCHECK(fd_ != -1);
+ }
+
+ ~TimerHandlerState() {
+ PCHECK(close(fd_) == 0);
+ }
+
+ void Setup(monotonic_clock::time_point base,
+ monotonic_clock::duration repeat_offset) override {
+ struct itimerspec new_value;
+ new_value.it_interval = ::aos::time::to_timespec(repeat_offset);
+ new_value.it_value = ::aos::time::to_timespec(base);
+ PCHECK(timerfd_settime(fd_, TFD_TIMER_ABSTIME, &new_value, nullptr) == 0);
+ }
+
+ void Disable() override {
+ // Disarm the timer by feeding zero values
+ Setup(::aos::monotonic_clock::epoch(), ::aos::monotonic_clock::zero());
+ }
+
+ void Run() {
+ thread_state_->WaitForStart();
+
+ while (true) {
+ uint64_t buf;
+ ssize_t result = read(fd_, &buf, sizeof(buf));
+ PCHECK(result != -1);
+ CHECK_EQ(result, static_cast<int>(sizeof(buf)));
+
+ {
+ MutexLocker locker(&thread_state_->mutex_);
+ if (!thread_state_->is_running()) break;
+ fn_();
+ // fn_ may have exited the event loop.
+ if (!thread_state_->is_running()) break;
+ }
+ }
+ }
+
+ private:
+ std::shared_ptr<ShmEventLoop::ThreadState> thread_state_;
+
+ // File descriptor for the timer
+ int fd_;
+
+ // Function to be run on the thread
+ ::std::function<void()> fn_;
+};
} // namespace internal
std::unique_ptr<RawFetcher> ShmEventLoop::MakeRawFetcher(
@@ -141,6 +198,19 @@
thread.detach();
}
+TimerHandler *ShmEventLoop::AddTimer(::std::function<void()> callback) {
+ internal::TimerHandlerState *timer =
+ new internal::TimerHandlerState(thread_state_, ::std::move(callback));
+
+ ::std::thread t([timer] {
+ timer->Run();
+ delete timer;
+ });
+ t.detach();
+
+ return timer;
+}
+
void ShmEventLoop::OnRun(std::function<void()> on_run) {
on_run_.push_back(std::move(on_run));
}