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