blob: 20a4d1385bd1f44215fdc755b82a19bc7c06908a [file] [log] [blame]
Jeff Browne839a582010-04-22 18:58:52 -07001//
2// Copyright 2010 The Android Open Source Project
3//
4// A select loop implementation.
5//
6#define LOG_TAG "PollLoop"
7
8//#define LOG_NDEBUG 0
9
10// Debugs poll and wake interactions.
11#define DEBUG_POLL_AND_WAKE 0
12
13// Debugs callback registration and invocation.
Jeff Brownf4a4ec22010-06-16 01:53:36 -070014#define DEBUG_CALLBACKS 0
Jeff Browne839a582010-04-22 18:58:52 -070015
16#include <cutils/log.h>
17#include <utils/PollLoop.h>
18
19#include <unistd.h>
20#include <fcntl.h>
21
22namespace android {
23
24PollLoop::PollLoop() :
Jeff Brownf4a4ec22010-06-16 01:53:36 -070025 mPolling(false), mWaiters(0) {
Jeff Browne839a582010-04-22 18:58:52 -070026 openWakePipe();
27}
28
29PollLoop::~PollLoop() {
30 closeWakePipe();
31}
32
33void PollLoop::openWakePipe() {
34 int wakeFds[2];
35 int result = pipe(wakeFds);
36 LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
37
38 mWakeReadPipeFd = wakeFds[0];
39 mWakeWritePipeFd = wakeFds[1];
40
41 result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
42 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
43 errno);
44
45 result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
46 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
47 errno);
48
49 // Add the wake pipe to the head of the request list with a null callback.
50 struct pollfd requestedFd;
51 requestedFd.fd = mWakeReadPipeFd;
52 requestedFd.events = POLLIN;
53 mRequestedFds.insertAt(requestedFd, 0);
54
55 RequestedCallback requestedCallback;
56 requestedCallback.callback = NULL;
57 requestedCallback.data = NULL;
58 mRequestedCallbacks.insertAt(requestedCallback, 0);
59}
60
61void PollLoop::closeWakePipe() {
62 close(mWakeReadPipeFd);
63 close(mWakeWritePipeFd);
64
65 // Note: We don't need to remove the poll structure or callback entry because this
66 // method is currently only called by the destructor.
67}
68
69bool PollLoop::pollOnce(int timeoutMillis) {
70 mLock.lock();
Jeff Brownf4a4ec22010-06-16 01:53:36 -070071 while (mWaiters != 0) {
72 mResume.wait(mLock);
73 }
Jeff Browne839a582010-04-22 18:58:52 -070074 mPolling = true;
75 mLock.unlock();
76
77 bool result;
78 size_t requestedCount = mRequestedFds.size();
79
80#if DEBUG_POLL_AND_WAKE
81 LOGD("%p ~ pollOnce - waiting on %d fds", this, requestedCount);
82 for (size_t i = 0; i < requestedCount; i++) {
83 LOGD(" fd %d - events %d", mRequestedFds[i].fd, mRequestedFds[i].events);
84 }
85#endif
86
87 int respondedCount = poll(mRequestedFds.editArray(), requestedCount, timeoutMillis);
88
89 if (respondedCount == 0) {
90 // Timeout
91#if DEBUG_POLL_AND_WAKE
92 LOGD("%p ~ pollOnce - timeout", this);
93#endif
94 result = false;
95 goto Done;
96 }
97
98 if (respondedCount < 0) {
99 // Error
100#if DEBUG_POLL_AND_WAKE
101 LOGD("%p ~ pollOnce - error, errno=%d", this, errno);
102#endif
103 if (errno != EINTR) {
104 LOGW("Poll failed with an unexpected error, errno=%d", errno);
105 }
106 result = false;
107 goto Done;
108 }
109
110#if DEBUG_POLL_AND_WAKE
111 LOGD("%p ~ pollOnce - handling responses from %d fds", this, respondedCount);
112 for (size_t i = 0; i < requestedCount; i++) {
113 LOGD(" fd %d - events %d, revents %d", mRequestedFds[i].fd, mRequestedFds[i].events,
114 mRequestedFds[i].revents);
115 }
116#endif
117
118 mPendingCallbacks.clear();
119 for (size_t i = 0; i < requestedCount; i++) {
120 const struct pollfd& requestedFd = mRequestedFds.itemAt(i);
121
122 short revents = requestedFd.revents;
123 if (revents) {
124 const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
125 Callback callback = requestedCallback.callback;
126
127 if (callback) {
128 PendingCallback pendingCallback;
129 pendingCallback.fd = requestedFd.fd;
130 pendingCallback.events = requestedFd.revents;
131 pendingCallback.callback = callback;
132 pendingCallback.data = requestedCallback.data;
133 mPendingCallbacks.push(pendingCallback);
134 } else {
135 if (requestedFd.fd == mWakeReadPipeFd) {
136#if DEBUG_POLL_AND_WAKE
137 LOGD("%p ~ pollOnce - awoken", this);
138#endif
139 char buffer[16];
140 ssize_t nRead;
141 do {
142 nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
143 } while (nRead == sizeof(buffer));
144 } else {
145#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
146 LOGD("%p ~ pollOnce - fd %d has no callback!", this, requestedFd.fd);
147#endif
148 }
149 }
150
151 respondedCount -= 1;
152 if (respondedCount == 0) {
153 break;
154 }
155 }
156 }
157 result = true;
158
159Done:
160 mLock.lock();
161 mPolling = false;
Jeff Brownf4a4ec22010-06-16 01:53:36 -0700162 if (mWaiters != 0) {
163 mAwake.broadcast();
164 }
Jeff Browne839a582010-04-22 18:58:52 -0700165 mLock.unlock();
166
167 if (result) {
168 size_t pendingCount = mPendingCallbacks.size();
169 for (size_t i = 0; i < pendingCount; i++) {
170 const PendingCallback& pendingCallback = mPendingCallbacks.itemAt(i);
171#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
172 LOGD("%p ~ pollOnce - invoking callback for fd %d", this, pendingCallback.fd);
173#endif
174
175 bool keep = pendingCallback.callback(pendingCallback.fd, pendingCallback.events,
176 pendingCallback.data);
177 if (! keep) {
178 removeCallback(pendingCallback.fd);
179 }
180 }
181 }
182
183#if DEBUG_POLL_AND_WAKE
184 LOGD("%p ~ pollOnce - done", this);
185#endif
186 return result;
187}
188
189void PollLoop::wake() {
190#if DEBUG_POLL_AND_WAKE
191 LOGD("%p ~ wake", this);
192#endif
193
194 ssize_t nWrite = write(mWakeWritePipeFd, "W", 1);
195 if (nWrite != 1) {
196 if (errno != EAGAIN) {
197 LOGW("Could not write wake signal, errno=%d", errno);
198 }
199 }
200}
201
202void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
203#if DEBUG_CALLBACKS
204 LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events);
205#endif
206
207 if (! events || ! callback) {
208 LOGE("Invalid attempt to set a callback with no selected poll events or no callback.");
209 removeCallback(fd);
210 return;
211 }
212
213 wakeAndLock();
214
215 struct pollfd requestedFd;
216 requestedFd.fd = fd;
217 requestedFd.events = events;
218
219 RequestedCallback requestedCallback;
220 requestedCallback.callback = callback;
221 requestedCallback.data = data;
222
223 ssize_t index = getRequestIndexLocked(fd);
224 if (index < 0) {
225 mRequestedFds.push(requestedFd);
226 mRequestedCallbacks.push(requestedCallback);
227 } else {
228 mRequestedFds.replaceAt(requestedFd, size_t(index));
229 mRequestedCallbacks.replaceAt(requestedCallback, size_t(index));
230 }
231
232 mLock.unlock();
233}
234
235bool PollLoop::removeCallback(int fd) {
236#if DEBUG_CALLBACKS
237 LOGD("%p ~ removeCallback - fd=%d", this, fd);
238#endif
239
240 wakeAndLock();
241
242 ssize_t index = getRequestIndexLocked(fd);
243 if (index >= 0) {
244 mRequestedFds.removeAt(size_t(index));
245 mRequestedCallbacks.removeAt(size_t(index));
246 }
247
248 mLock.unlock();
249 return index >= 0;
250}
251
252ssize_t PollLoop::getRequestIndexLocked(int fd) {
253 size_t requestCount = mRequestedFds.size();
254
255 for (size_t i = 0; i < requestCount; i++) {
256 if (mRequestedFds.itemAt(i).fd == fd) {
257 return i;
258 }
259 }
260
261 return -1;
262}
263
264void PollLoop::wakeAndLock() {
265 mLock.lock();
Jeff Brownf4a4ec22010-06-16 01:53:36 -0700266 mWaiters += 1;
Jeff Browne839a582010-04-22 18:58:52 -0700267 while (mPolling) {
268 wake();
269 mAwake.wait(mLock);
270 }
Jeff Brownf4a4ec22010-06-16 01:53:36 -0700271 mWaiters -= 1;
272 if (mWaiters == 0) {
273 mResume.signal();
274 }
Jeff Browne839a582010-04-22 18:58:52 -0700275}
276
277} // namespace android