epoll_event_dispatcher.cpp revision a8a92784bc5f6a50ce00311c6161fbcfc0898c5a
1#include "epoll_event_dispatcher.h"
2
3#include <log/log.h>
4#include <sys/epoll.h>
5#include <sys/eventfd.h>
6#include <sys/prctl.h>
7
8#include <dvr/performance_client_api.h>
9
10namespace android {
11namespace dvr {
12
13EpollEventDispatcher::EpollEventDispatcher()
14    : exit_thread_(false), epoll_fd_(-1), event_fd_(-1) {
15  epoll_fd_ = epoll_create(64);
16  if (epoll_fd_ < 0) {
17    ALOGE("Failed to create epoll fd: %s", strerror(errno));
18    return;
19  }
20
21  event_fd_ = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
22  if (event_fd_ < 0) {
23    ALOGE("Failed to create event for epolling: %s", strerror(errno));
24    return;
25  }
26
27  // Add watch for eventfd. This should only watch for EPOLLIN, which gets set
28  // when eventfd_write occurs. Use "this" as a unique sentinal value to
29  // identify events from the event fd.
30  epoll_event event = {.events = EPOLLIN, .data = {.ptr = this}};
31  if (epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, event_fd_, &event) < 0) {
32    ALOGE("Failed to add eventfd to epoll set because: %s", strerror(errno));
33    return;
34  }
35
36  thread_ = std::thread(&EpollEventDispatcher::EventThread, this);
37}
38
39EpollEventDispatcher::~EpollEventDispatcher() {
40  Stop();
41
42  close(epoll_fd_);
43  close(event_fd_);
44}
45
46void EpollEventDispatcher::Stop() {
47  exit_thread_.store(true);
48  eventfd_write(event_fd_, 1);
49}
50
51int EpollEventDispatcher::AddEventHandler(int fd, int event_mask,
52                                          Handler handler) {
53  std::lock_guard<std::mutex> lock(lock_);
54
55  epoll_event event;
56  event.events = event_mask;
57  event.data.ptr = &(handlers_[fd] = handler);
58
59  ALOGD_IF(
60      TRACE,
61      "EpollEventDispatcher::AddEventHandler: fd=%d event_mask=0x%x handler=%p",
62      fd, event_mask, event.data.ptr);
63
64  int err = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &event);
65  return err < 0 ? -errno : 0;
66}
67
68int EpollEventDispatcher::RemoveEventHandler(int fd) {
69  ALOGD_IF(TRACE, "EpollEventDispatcher::RemoveEventHandler: fd=%d", fd);
70  std::lock_guard<std::mutex> lock(lock_);
71
72  epoll_event dummy;  // See BUGS in man 2 epoll_ctl.
73  if (epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, &dummy) < 0) {
74    ALOGE("Failed to remove fd from epoll set because: %s", strerror(errno));
75    return -errno;
76  }
77
78  // If the fd was valid above, add it to the list of ids to remove.
79  removed_handlers_.push_back(fd);
80
81  // Wake up the event thread to clean up.
82  eventfd_write(event_fd_, 1);
83
84  return 0;
85}
86
87void EpollEventDispatcher::EventThread() {
88  prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("EpollEvent"), 0, 0, 0);
89
90  const int error = dvrSetSchedulerClass(0, "graphics");
91  LOG_ALWAYS_FATAL_IF(
92      error < 0,
93      "EpollEventDispatcher::EventThread: Failed to set scheduler class: %s",
94      strerror(-error));
95
96  const size_t kMaxNumEvents = 128;
97  epoll_event events[kMaxNumEvents];
98
99  while (!exit_thread_.load()) {
100    int num_events = epoll_wait(epoll_fd_, events, kMaxNumEvents, -1);
101    if (num_events < 0 && errno != EINTR)
102      break;
103
104    ALOGD_IF(TRACE, "EpollEventDispatcher::EventThread: num_events=%d",
105             num_events);
106
107    for (int i = 0; i < num_events; i++) {
108      ALOGD_IF(
109          TRACE,
110          "EpollEventDispatcher::EventThread: event %d: handler=%p events=0x%x",
111          i, events[i].data.ptr, events[i].events);
112
113      if (events[i].data.ptr == this) {
114        // Clear pending event on event_fd_. Serialize the read with respect to
115        // writes from other threads.
116        std::lock_guard<std::mutex> lock(lock_);
117        eventfd_t value;
118        eventfd_read(event_fd_, &value);
119      } else {
120        auto handler = reinterpret_cast<Handler*>(events[i].data.ptr);
121        if (handler)
122          (*handler)(events[i].events);
123      }
124    }
125
126    // Remove any handlers that have been posted for removal. This is done here
127    // instead of in RemoveEventHandler() to prevent races between the dispatch
128    // thread and the code requesting the removal. Handlers are guaranteed to
129    // stay alive between exiting epoll_wait() and the dispatch loop above.
130    std::lock_guard<std::mutex> lock(lock_);
131    for (auto handler_fd : removed_handlers_) {
132      ALOGD_IF(TRACE,
133               "EpollEventDispatcher::EventThread: removing handler: fd=%d",
134               handler_fd);
135      handlers_.erase(handler_fd);
136    }
137    removed_handlers_.clear();
138  }
139}
140
141}  // namespace dvr
142}  // namespace android
143