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