blob: 1cf5f17f629416140c380e995d92dfc4a5dd0707 [file] [log] [blame]
Corey Tabaka2251d822017-04-20 16:04:07 -07001#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() {
Nick Kralevichfcf1b2b2018-12-15 11:59:30 -080014 epoll_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
Corey Tabaka2251d822017-04-20 16:04:07 -070015 if (!epoll_fd_) {
16 ALOGE("Failed to create epoll fd: %s", strerror(errno));
17 return;
18 }
19
20 event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
21 if (!event_fd_) {
22 ALOGE("Failed to create event for epolling: %s", strerror(errno));
23 return;
24 }
25
26 // Add watch for eventfd. This should only watch for EPOLLIN, which gets set
27 // when eventfd_write occurs. Use "this" as a unique sentinal value to
28 // identify events from the event fd.
29 epoll_event event = {.events = EPOLLIN, .data = {.ptr = this}};
30 if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, event_fd_.Get(), &event) < 0) {
31 ALOGE("Failed to add eventfd to epoll set because: %s", strerror(errno));
32 return;
33 }
34
35 thread_ = std::thread(&EpollEventDispatcher::EventThread, this);
36}
37
38EpollEventDispatcher::~EpollEventDispatcher() { Stop(); }
39
40void EpollEventDispatcher::Stop() {
41 exit_thread_.store(true);
42 eventfd_write(event_fd_.Get(), 1);
43}
44
45pdx::Status<void> EpollEventDispatcher::AddEventHandler(int fd, int event_mask,
46 Handler handler) {
47 std::lock_guard<std::mutex> lock(lock_);
48
49 epoll_event event;
50 event.events = event_mask;
51 event.data.ptr = &(handlers_[fd] = handler);
52
53 ALOGD_IF(
54 TRACE,
55 "EpollEventDispatcher::AddEventHandler: fd=%d event_mask=0x%x handler=%p",
56 fd, event_mask, event.data.ptr);
57
58 if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, fd, &event) < 0) {
59 const int error = errno;
60 ALOGE("Failed to add fd to epoll set because: %s", strerror(error));
61 return pdx::ErrorStatus(error);
62 } else {
63 return {};
64 }
65}
66
67pdx::Status<void> EpollEventDispatcher::RemoveEventHandler(int fd) {
68 ALOGD_IF(TRACE, "EpollEventDispatcher::RemoveEventHandler: fd=%d", fd);
69 std::lock_guard<std::mutex> lock(lock_);
70
71 epoll_event dummy; // See BUGS in man 2 epoll_ctl.
72 if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, fd, &dummy) < 0) {
73 const int error = errno;
74 ALOGE("Failed to remove fd from epoll set because: %s", strerror(error));
75 return pdx::ErrorStatus(error);
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_.Get(), 1);
83
84 return {};
85}
86
87void EpollEventDispatcher::EventThread() {
88 prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrEvent"), 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 const int num_events = epoll_wait(epoll_fd_.Get(), events, kMaxNumEvents, -1);
101 if (num_events < 0 && errno != EINTR)
102 break;
103
Corey Tabaka89bbefc2017-06-06 16:14:21 -0700104 ALOGD_IF(TRACE > 1, "EpollEventDispatcher::EventThread: num_events=%d",
Corey Tabaka2251d822017-04-20 16:04:07 -0700105 num_events);
106
107 for (int i = 0; i < num_events; i++) {
108 ALOGD_IF(
Corey Tabaka89bbefc2017-06-06 16:14:21 -0700109 TRACE > 1,
Corey Tabaka2251d822017-04-20 16:04:07 -0700110 "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_.Get(), &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