Home | History | Annotate | Download | only in libvrflinger
      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 
     10 namespace android {
     11 namespace dvr {
     12 
     13 EpollEventDispatcher::EpollEventDispatcher() {
     14   epoll_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
     15   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 
     38 EpollEventDispatcher::~EpollEventDispatcher() { Stop(); }
     39 
     40 void EpollEventDispatcher::Stop() {
     41   exit_thread_.store(true);
     42   eventfd_write(event_fd_.Get(), 1);
     43 }
     44 
     45 pdx::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 
     67 pdx::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 
     87 void 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 
    104     ALOGD_IF(TRACE > 1, "EpollEventDispatcher::EventThread: num_events=%d",
    105              num_events);
    106 
    107     for (int i = 0; i < num_events; i++) {
    108       ALOGD_IF(
    109           TRACE > 1,
    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_.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
    143