12251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka#include "epoll_event_dispatcher.h" 22251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 32251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka#include <log/log.h> 42251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka#include <sys/epoll.h> 52251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka#include <sys/eventfd.h> 62251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka#include <sys/prctl.h> 72251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 82251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka#include <dvr/performance_client_api.h> 92251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 102251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabakanamespace android { 112251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabakanamespace dvr { 122251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 132251d822dac2a96aad4184a6fdc2690f0a58af7cCorey TabakaEpollEventDispatcher::EpollEventDispatcher() { 142251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka epoll_fd_.Reset(epoll_create(64)); 152251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka if (!epoll_fd_) { 162251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGE("Failed to create epoll fd: %s", strerror(errno)); 172251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return; 182251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka } 192251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 202251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); 212251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka if (!event_fd_) { 222251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGE("Failed to create event for epolling: %s", strerror(errno)); 232251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return; 242251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka } 252251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 262251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka // Add watch for eventfd. This should only watch for EPOLLIN, which gets set 272251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka // when eventfd_write occurs. Use "this" as a unique sentinal value to 282251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka // identify events from the event fd. 292251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka epoll_event event = {.events = EPOLLIN, .data = {.ptr = this}}; 302251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, event_fd_.Get(), &event) < 0) { 312251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGE("Failed to add eventfd to epoll set because: %s", strerror(errno)); 322251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return; 332251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka } 342251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 352251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka thread_ = std::thread(&EpollEventDispatcher::EventThread, this); 362251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka} 372251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 382251d822dac2a96aad4184a6fdc2690f0a58af7cCorey TabakaEpollEventDispatcher::~EpollEventDispatcher() { Stop(); } 392251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 402251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabakavoid EpollEventDispatcher::Stop() { 412251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka exit_thread_.store(true); 422251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka eventfd_write(event_fd_.Get(), 1); 432251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka} 442251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 452251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabakapdx::Status<void> EpollEventDispatcher::AddEventHandler(int fd, int event_mask, 462251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka Handler handler) { 472251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka std::lock_guard<std::mutex> lock(lock_); 482251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 492251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka epoll_event event; 502251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka event.events = event_mask; 512251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka event.data.ptr = &(handlers_[fd] = handler); 522251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 532251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGD_IF( 542251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka TRACE, 552251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka "EpollEventDispatcher::AddEventHandler: fd=%d event_mask=0x%x handler=%p", 562251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka fd, event_mask, event.data.ptr); 572251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 582251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, fd, &event) < 0) { 592251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka const int error = errno; 602251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGE("Failed to add fd to epoll set because: %s", strerror(error)); 612251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return pdx::ErrorStatus(error); 622251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka } else { 632251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return {}; 642251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka } 652251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka} 662251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 672251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabakapdx::Status<void> EpollEventDispatcher::RemoveEventHandler(int fd) { 682251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGD_IF(TRACE, "EpollEventDispatcher::RemoveEventHandler: fd=%d", fd); 692251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka std::lock_guard<std::mutex> lock(lock_); 702251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 712251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka epoll_event dummy; // See BUGS in man 2 epoll_ctl. 722251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, fd, &dummy) < 0) { 732251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka const int error = errno; 742251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGE("Failed to remove fd from epoll set because: %s", strerror(error)); 752251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return pdx::ErrorStatus(error); 762251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka } 772251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 782251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka // If the fd was valid above, add it to the list of ids to remove. 792251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka removed_handlers_.push_back(fd); 802251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 812251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka // Wake up the event thread to clean up. 822251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka eventfd_write(event_fd_.Get(), 1); 832251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 842251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return {}; 852251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka} 862251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 872251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabakavoid EpollEventDispatcher::EventThread() { 882251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrEvent"), 0, 0, 0); 892251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 902251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka const int error = dvrSetSchedulerClass(0, "graphics"); 912251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka LOG_ALWAYS_FATAL_IF( 922251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka error < 0, 932251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka "EpollEventDispatcher::EventThread: Failed to set scheduler class: %s", 942251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka strerror(-error)); 952251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 962251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka const size_t kMaxNumEvents = 128; 972251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka epoll_event events[kMaxNumEvents]; 982251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 992251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka while (!exit_thread_.load()) { 1002251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka const int num_events = epoll_wait(epoll_fd_.Get(), events, kMaxNumEvents, -1); 1012251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka if (num_events < 0 && errno != EINTR) 1022251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka break; 1032251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 1042251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGD_IF(TRACE, "EpollEventDispatcher::EventThread: num_events=%d", 1052251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka num_events); 1062251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 1072251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka for (int i = 0; i < num_events; i++) { 1082251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGD_IF( 1092251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka TRACE, 1102251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka "EpollEventDispatcher::EventThread: event %d: handler=%p events=0x%x", 1112251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka i, events[i].data.ptr, events[i].events); 1122251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 1132251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka if (events[i].data.ptr == this) { 1142251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka // Clear pending event on event_fd_. Serialize the read with respect to 1152251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka // writes from other threads. 1162251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka std::lock_guard<std::mutex> lock(lock_); 1172251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka eventfd_t value; 1182251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka eventfd_read(event_fd_.Get(), &value); 1192251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka } else { 1202251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka auto handler = reinterpret_cast<Handler*>(events[i].data.ptr); 1212251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka if (handler) 1222251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka (*handler)(events[i].events); 1232251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka } 1242251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka } 1252251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 1262251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka // Remove any handlers that have been posted for removal. This is done here 1272251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka // instead of in RemoveEventHandler() to prevent races between the dispatch 1282251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka // thread and the code requesting the removal. Handlers are guaranteed to 1292251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka // stay alive between exiting epoll_wait() and the dispatch loop above. 1302251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka std::lock_guard<std::mutex> lock(lock_); 1312251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka for (auto handler_fd : removed_handlers_) { 1322251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGD_IF(TRACE, 1332251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka "EpollEventDispatcher::EventThread: removing handler: fd=%d", 1342251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka handler_fd); 1352251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka handlers_.erase(handler_fd); 1362251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka } 1372251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka removed_handlers_.clear(); 1382251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka } 1392251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka} 1402251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 1412251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka} // namespace dvr 1422251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka} // namespace android 143