15a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko#include <pdx/service_dispatcher.h> 2e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 3e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <errno.h> 4e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <log/log.h> 5e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <sys/epoll.h> 6e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <sys/eventfd.h> 7e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 85a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko#include <pdx/service.h> 95a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko#include <pdx/service_endpoint.h> 10e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 11e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkostatic const int kMaxEventsPerLoop = 128; 12e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 13e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace android { 14e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace pdx { 15e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 165a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenkostd::unique_ptr<ServiceDispatcher> ServiceDispatcher::Create() { 17e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko std::unique_ptr<ServiceDispatcher> dispatcher{new ServiceDispatcher()}; 18e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (!dispatcher->epoll_fd_ || !dispatcher->event_fd_) { 19e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko dispatcher.reset(); 20e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 21e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 225a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko return dispatcher; 23e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 24e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 25e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex VakulenkoServiceDispatcher::ServiceDispatcher() { 26e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); 27e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (!event_fd_) { 28e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ALOGE("Failed to create event fd because: %s\n", strerror(errno)); 29e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return; 30e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 31e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 32409c6eecdca80e95a110d63bc70b1c2dfcf49100Alex Vakulenko epoll_fd_.Reset(epoll_create1(EPOLL_CLOEXEC)); 33e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (!epoll_fd_) { 34e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ALOGE("Failed to create epoll fd because: %s\n", strerror(errno)); 35e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return; 36e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 37e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 38e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Use "this" as a unique pointer to distinguish the event fd from all 39e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // the other entries that point to instances of Service. 40e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko epoll_event event; 41e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko event.events = EPOLLIN; 42e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko event.data.ptr = this; 43e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 44e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, event_fd_.Get(), &event) < 0) { 45e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ALOGE("Failed to add event fd to epoll fd because: %s\n", strerror(errno)); 46e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 47e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Close the fds here and signal failure to the factory method. 48e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko event_fd_.Close(); 49e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko epoll_fd_.Close(); 50e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 51e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 52e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 53e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex VakulenkoServiceDispatcher::~ServiceDispatcher() { SetCanceled(true); } 54e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 55e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkoint ServiceDispatcher::ThreadEnter() { 56e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko std::lock_guard<std::mutex> autolock(mutex_); 57e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 58e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (canceled_) 59e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return -EBUSY; 60e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 61e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko thread_count_++; 62e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return 0; 63e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 64e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 65e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkovoid ServiceDispatcher::ThreadExit() { 66e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko std::lock_guard<std::mutex> autolock(mutex_); 67e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko thread_count_--; 68e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko condition_.notify_one(); 69e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 70e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 71e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkoint ServiceDispatcher::AddService(const std::shared_ptr<Service>& service) { 72e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko std::lock_guard<std::mutex> autolock(mutex_); 73e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 74e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko epoll_event event; 75e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko event.events = EPOLLIN; 76e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko event.data.ptr = service.get(); 77e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 785a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, service->endpoint()->epoll_fd(), 795a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko &event) < 0) { 80e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ALOGE("Failed to add service to dispatcher because: %s\n", strerror(errno)); 81e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return -errno; 82e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 83e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 84e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko services_.push_back(service); 85e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return 0; 86e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 87e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 88e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkoint ServiceDispatcher::RemoveService(const std::shared_ptr<Service>& service) { 89e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko std::lock_guard<std::mutex> autolock(mutex_); 90e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 91e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // It's dangerous to remove a service while other threads may be using it. 92e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (thread_count_ > 0) 93e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return -EBUSY; 94e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 95e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko epoll_event dummy; // See BUGS in man 2 epoll_ctl. 965a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, service->endpoint()->epoll_fd(), 975a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko &dummy) < 0) { 98e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ALOGE("Failed to remove service from dispatcher because: %s\n", 99e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko strerror(errno)); 100e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return -errno; 101e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 102e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 1035a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko services_.erase(std::remove(services_.begin(), services_.end(), service), 1045a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko services_.end()); 105e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return 0; 106e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 107e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 108e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkoint ServiceDispatcher::ReceiveAndDispatch() { return ReceiveAndDispatch(-1); } 109e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 110e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkoint ServiceDispatcher::ReceiveAndDispatch(int timeout) { 111e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko int ret = ThreadEnter(); 112e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (ret < 0) 113e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return ret; 114e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 115e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko epoll_event events[kMaxEventsPerLoop]; 116e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 117e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko int count = epoll_wait(epoll_fd_.Get(), events, kMaxEventsPerLoop, timeout); 118e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (count <= 0) { 119e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ALOGE_IF(count < 0, "Failed to wait for epoll events because: %s\n", 120e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko strerror(errno)); 121e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ThreadExit(); 122e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return count < 0 ? -errno : -ETIMEDOUT; 123e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 124e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 125e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko for (int i = 0; i < count; i++) { 126e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (events[i].data.ptr == this) { 127e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ThreadExit(); 128e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return -EBUSY; 129e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } else { 130e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Service* service = static_cast<Service*>(events[i].data.ptr); 131e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 132e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ALOGI_IF(TRACE, "Dispatching message: fd=%d\n", 1335a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko service->endpoint()->epoll_fd()); 134e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko service->ReceiveAndDispatch(); 135e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 136e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 137e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 138e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ThreadExit(); 139e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return 0; 140e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 141e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 142e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkoint ServiceDispatcher::EnterDispatchLoop() { 143e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko int ret = ThreadEnter(); 144e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (ret < 0) 145e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return ret; 146e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 147e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko epoll_event events[kMaxEventsPerLoop]; 148e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 149e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko while (!IsCanceled()) { 150e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko int count = epoll_wait(epoll_fd_.Get(), events, kMaxEventsPerLoop, -1); 151e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (count < 0 && errno != EINTR) { 152e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ALOGE("Failed to wait for epoll events because: %s\n", strerror(errno)); 153e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ThreadExit(); 154e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return -errno; 155e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 156e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 157e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko for (int i = 0; i < count; i++) { 158e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (events[i].data.ptr == this) { 159e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ThreadExit(); 160e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return -EBUSY; 161e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } else { 162e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Service* service = static_cast<Service*>(events[i].data.ptr); 163e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 164e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ALOGI_IF(TRACE, "Dispatching message: fd=%d\n", 1655a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko service->endpoint()->epoll_fd()); 166e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko service->ReceiveAndDispatch(); 167e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 168e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 169e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 170e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 171e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ThreadExit(); 172e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return 0; 173e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 174e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 175e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkovoid ServiceDispatcher::SetCanceled(bool cancel) { 176e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko std::unique_lock<std::mutex> lock(mutex_); 177e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko canceled_ = cancel; 178e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 179e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (canceled_ && thread_count_ > 0) { 180e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko eventfd_write(event_fd_.Get(), 1); // Signal threads to quit. 181e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 182e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko condition_.wait(lock, [this] { return !(canceled_ && thread_count_ > 0); }); 183e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 184e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko eventfd_t value; 185e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko eventfd_read(event_fd_.Get(), &value); // Unsignal. 186e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 187e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 188e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 189e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkobool ServiceDispatcher::IsCanceled() const { return canceled_; } 190e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 191e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} // namespace pdx 192e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} // namespace android 193