summaryrefslogtreecommitdiff
path: root/libs/vr/libpdx_uds/channel_event_set.cpp
blob: c68968e1f209b085693fccd6fb18f1972b3e4018 (plain)
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
143
144
145
146
147
148
149
150
#include "private/uds/channel_event_set.h"

#include <errno.h>
#include <log/log.h>
#include <poll.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>

#include <uds/ipc_helper.h>

namespace android {
namespace pdx {
namespace uds {

namespace {

template <typename FileHandleType>
Status<void> SetupHandle(int fd, FileHandleType* handle,
                         const char* error_name) {
  const int error = errno;
  handle->Reset(fd);
  if (!*handle) {
    ALOGE("SetupHandle: Failed to setup %s handle: %s", error_name,
          strerror(error));
    return ErrorStatus{error};
  }
  return {};
}

}  // anonymous namespace

ChannelEventSet::ChannelEventSet() {
  const int flags = EFD_CLOEXEC | EFD_NONBLOCK;
  LocalHandle pollin_event_fd, pollhup_event_fd;

  if (!SetupHandle(eventfd(0, flags), &pollin_event_fd, "pollin_event") ||
      !SetupHandle(eventfd(0, flags), &pollhup_event_fd, "pollhup_event")) {
    return;
  }

  pollin_event_fd_ = std::move(pollin_event_fd);
  pollhup_event_fd_ = std::move(pollhup_event_fd);
}

int ChannelEventSet::ModifyEvents(int clear_mask, int set_mask) {
  ALOGD_IF(TRACE, "ChannelEventSet::ModifyEvents: clear_mask=%x set_mask=%x",
           clear_mask, set_mask);
  const int old_bits = event_bits_;
  const int new_bits = (event_bits_ & ~clear_mask) | set_mask;
  event_bits_ = new_bits;
  eventfd_t value;

  // Calculate which bits changed and how. Bits that haven't changed since last
  // modification will not change the state of an eventfd.
  const int set_bits = new_bits & ~old_bits;
  const int clear_bits = ~new_bits & old_bits;

  if (set_bits & EPOLLIN)
    eventfd_write(pollin_event_fd_.Get(), 1);
  else if (clear_bits & EPOLLIN)
    eventfd_read(pollin_event_fd_.Get(), &value);

  if (set_bits & EPOLLHUP)
    eventfd_write(pollhup_event_fd_.Get(), 1);
  else if (clear_bits & EPOLLHUP)
    eventfd_read(pollhup_event_fd_.Get(), &value);

  return 0;
}

ChannelEventReceiver::ChannelEventReceiver(LocalHandle data_fd,
                                           LocalHandle pollin_event_fd,
                                           LocalHandle pollhup_event_fd) {
  LocalHandle epoll_fd;
  if (!SetupHandle(epoll_create1(EPOLL_CLOEXEC), &epoll_fd, "epoll")) {
    return;
  }

  epoll_event event;
  event.events = EPOLLHUP | EPOLLRDHUP;
  event.data.u32 = 0;
  if (epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, data_fd.Get(), &event) < 0) {
    const int error = errno;
    ALOGE("ChannelEventSet::ChannelEventSet: Failed to add data_fd: %s",
          strerror(error));
    return;
  }

  event.events = EPOLLIN;
  event.data.u32 = 0;
  if (epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, pollin_event_fd.Get(), &event) <
      0) {
    const int error = errno;
    ALOGE("ChannelEventSet::ChannelEventSet: Failed to add pollin_event_fd: %s",
          strerror(error));
    return;
  }

  event.events = EPOLLIN;
  event.data.u32 = 0;
  if (epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, pollhup_event_fd.Get(), &event) <
      0) {
    const int error = errno;
    ALOGE(
        "ChannelEventSet::ChannelEventSet: Failed to add pollhup_event_fd: %s",
        strerror(error));
    return;
  }

  pollin_event_fd_ = std::move(pollin_event_fd);
  pollhup_event_fd_ = std::move(pollhup_event_fd);
  data_fd_ = std::move(data_fd);
  epoll_fd_ = std::move(epoll_fd);
}

Status<int> ChannelEventReceiver::PollPendingEvents(int timeout_ms) const {
  std::array<pollfd, 3> pfds = {{{pollin_event_fd_.Get(), POLLIN, 0},
                                 {pollhup_event_fd_.Get(), POLLIN, 0},
                                 {data_fd_.Get(), POLLHUP | POLLRDHUP, 0}}};
  if (RETRY_EINTR(poll(pfds.data(), pfds.size(), timeout_ms)) < 0) {
    const int error = errno;
    ALOGE(
        "ChannelEventReceiver::PollPendingEvents: Failed to poll for events: "
        "%s",
        strerror(error));
    return ErrorStatus{error};
  }

  const int event_mask =
      ((pfds[0].revents & POLLIN) ? EPOLLIN : 0) |
      ((pfds[1].revents & POLLIN) ? EPOLLHUP : 0) |
      ((pfds[2].revents & (POLLHUP | POLLRDHUP)) ? EPOLLHUP : 0);
  return {event_mask};
}

Status<int> ChannelEventReceiver::GetPendingEvents() const {
  constexpr long kTimeoutMs = 0;
  return PollPendingEvents(kTimeoutMs);
}

std::vector<ClientChannel::EventSource> ChannelEventReceiver::GetEventSources()
    const {
  return {{data_fd_.Get(), EPOLLHUP | EPOLLRDHUP},
          {pollin_event_fd_.Get(), EPOLLIN},
          {pollhup_event_fd_.Get(), POLLIN}};
}

}  // namespace uds
}  // namespace pdx
}  // namespace android