14615e0d5aa416ab1a8596bde68f71f7ebe431b86Vitaly Buka// Copyright 2015 The Weave Authors. All rights reserved.
217b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka// Use of this source code is governed by a BSD-style license that can be
317b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka// found in the LICENSE file.
417b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka
53523fdd2a071c7b918761cf82f1ac0ff73188093Johan Euphrosine#include "examples/provider/event_task_runner.h"
617b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka
717b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka#include <signal.h>
817b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka
917b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Bukanamespace weave {
1017b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Bukanamespace examples {
1117b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka
1217b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Bukanamespace {
1317b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Bukaevent_base* g_event_base = nullptr;
1417b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka}
1517b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka
1617b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Bukavoid EventTaskRunner::PostDelayedTask(
1717b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka    const tracked_objects::Location& from_here,
1817b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka    const base::Closure& task,
1917b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka    base::TimeDelta delay) {
2017b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  base::Time new_time = base::Time::Now() + delay;
2117b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  if (queue_.empty() || new_time < queue_.top().first.first) {
2217b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka    ReScheduleEvent(delay);
2317b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  }
2417b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  queue_.emplace(std::make_pair(new_time, ++counter_), task);
2517b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka}
2617b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka
27f1fa93dae92d1f4a2e264200ae3f085e19421293ilewisvoid EventTaskRunner::AddIoCompletionTask(
28f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis    int fd,
29f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis    int16_t what,
30f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis    const EventTaskRunner::IoCompletionCallback& task) {
31f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis  int16_t flags = EV_PERSIST | EV_ET;
32f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis  flags |= (what & kReadable) ? EV_READ : 0;
33f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis  flags |= (what & kWriteable) ? EV_WRITE : 0;
34331355869fb6f8e11427f35807b7c310ec7743caJacob Marble#if LIBEVENT_VERSION_NUMBER >= 0x02010400
35f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis  flags |= (what & kClosed) ? EV_CLOSED : 0;
36331355869fb6f8e11427f35807b7c310ec7743caJacob Marble#endif
37f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis  event* ioevent = event_new(base_.get(), fd, flags, FdEventHandler, this);
38f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis  EventPtr<event> ioeventPtr{ioevent};
3952d006a131c61955e3a8a915d7f22941b3a4eee2Vitaly Buka  fd_task_map_.insert(
4052d006a131c61955e3a8a915d7f22941b3a4eee2Vitaly Buka      std::make_pair(fd, std::make_pair(std::move(ioeventPtr), task)));
41f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis  event_add(ioevent, nullptr);
42f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis}
43f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis
44f1fa93dae92d1f4a2e264200ae3f085e19421293ilewisvoid EventTaskRunner::RemoveIoCompletionTask(int fd) {
45f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis  fd_task_map_.erase(fd);
46f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis}
47f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis
4817b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Bukavoid EventTaskRunner::Run() {
4917b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  g_event_base = base_.get();
5017b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka
5117b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  struct sigaction sa = {};
5217b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  sa.sa_handler = [](int signal) {
5317b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka    event_base_loopexit(g_event_base, nullptr);
5417b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  };
5517b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  sigfillset(&sa.sa_mask);
5617b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  sigaction(SIGINT, &sa, nullptr);
5717b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka
58331355869fb6f8e11427f35807b7c310ec7743caJacob Marble  do {
59331355869fb6f8e11427f35807b7c310ec7743caJacob Marble    event_base_loop(g_event_base, EVLOOP_ONCE);
60331355869fb6f8e11427f35807b7c310ec7743caJacob Marble  } while (!event_base_got_exit(g_event_base));
6117b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  g_event_base = nullptr;
6217b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka}
6317b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka
6417b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Bukavoid EventTaskRunner::ReScheduleEvent(base::TimeDelta delay) {
6517b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  timespec ts = delay.ToTimeSpec();
6617b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  timeval tv = {ts.tv_sec, ts.tv_nsec / 1000};
6717b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  event_add(task_event_.get(), &tv);
6817b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka}
6917b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka
70f1fa93dae92d1f4a2e264200ae3f085e19421293ilewisvoid EventTaskRunner::EventHandler(int /* fd */,
71f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis                                   int16_t /* what */,
72f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis                                   void* runner) {
7317b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  static_cast<EventTaskRunner*>(runner)->Process();
7417b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka}
7517b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka
7617b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Bukavoid EventTaskRunner::FreeEvent(event* evnt) {
7717b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  event_del(evnt);
7817b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  event_free(evnt);
7917b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka}
8017b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka
8117b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Bukavoid EventTaskRunner::Process() {
8217b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  while (!queue_.empty() && queue_.top().first.first <= base::Time::Now()) {
8317b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka    auto cb = queue_.top().second;
8417b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka    queue_.pop();
8517b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka    cb.Run();
8617b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  }
8717b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  if (!queue_.empty()) {
8817b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka    base::TimeDelta delta = std::max(
8917b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka        base::TimeDelta(), queue_.top().first.first - base::Time::Now());
9017b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka    ReScheduleEvent(delta);
9117b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka  }
9217b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka}
9317b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka
94f1fa93dae92d1f4a2e264200ae3f085e19421293ilewisvoid EventTaskRunner::FdEventHandler(int fd, int16_t what, void* runner) {
95f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis  static_cast<EventTaskRunner*>(runner)->ProcessFd(fd, what);
96f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis}
97f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis
98f1fa93dae92d1f4a2e264200ae3f085e19421293ilewisvoid EventTaskRunner::ProcessFd(int fd, int16_t what) {
99f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis  auto it = fd_task_map_.find(fd);
100f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis  if (it != fd_task_map_.end()) {
101f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis    const IoCompletionCallback& callback = it->second.second;
102f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis    callback.Run(fd, what, this);
103f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis  }
104f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis}
105f1fa93dae92d1f4a2e264200ae3f085e19421293ilewis
10617b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka}  // namespace examples
10717b0a8af760d75209e068d5e5479f6d849195ae5Vitaly Buka}  // namespace weave
108