blob: 6d3eeee15cfcd7f06734988c02a570dc4a7fb57e [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
Dianne Hackbornefa10852010-07-02 18:52:01 -070024static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
25static bool gHaveTLS = false;
26static pthread_key_t gTLS = 0;
27
Dianne Hackborn3c5d1252010-07-07 14:27:31 -070028PollLoop::PollLoop(bool allowNonCallbacks) :
29 mAllowNonCallbacks(allowNonCallbacks), mPolling(false),
30 mWaiters(0), mPendingFdsPos(0) {
Jeff Browne839a582010-04-22 18:58:52 -070031 openWakePipe();
32}
33
34PollLoop::~PollLoop() {
35 closeWakePipe();
36}
37
Dianne Hackbornefa10852010-07-02 18:52:01 -070038void PollLoop::threadDestructor(void *st) {
39 PollLoop* const self = static_cast<PollLoop*>(st);
40 if (self != NULL) {
41 self->decStrong((void*)threadDestructor);
42 }
43}
44
45void PollLoop::setForThread(const sp<PollLoop>& pollLoop) {
46 sp<PollLoop> old = getForThread();
47
48 if (pollLoop != NULL) {
49 pollLoop->incStrong((void*)threadDestructor);
50 }
51
52 pthread_setspecific(gTLS, pollLoop.get());
53
54 if (old != NULL) {
55 old->decStrong((void*)threadDestructor);
56 }
57}
58
59sp<PollLoop> PollLoop::getForThread() {
60 if (!gHaveTLS) {
61 pthread_mutex_lock(&gTLSMutex);
62 if (pthread_key_create(&gTLS, threadDestructor) != 0) {
63 pthread_mutex_unlock(&gTLSMutex);
64 return NULL;
65 }
66 gHaveTLS = true;
67 pthread_mutex_unlock(&gTLSMutex);
68 }
69
70 return (PollLoop*)pthread_getspecific(gTLS);
71}
72
Jeff Browne839a582010-04-22 18:58:52 -070073void PollLoop::openWakePipe() {
74 int wakeFds[2];
75 int result = pipe(wakeFds);
76 LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
77
78 mWakeReadPipeFd = wakeFds[0];
79 mWakeWritePipeFd = wakeFds[1];
80
81 result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
82 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
83 errno);
84
85 result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
86 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
87 errno);
88
89 // Add the wake pipe to the head of the request list with a null callback.
90 struct pollfd requestedFd;
91 requestedFd.fd = mWakeReadPipeFd;
92 requestedFd.events = POLLIN;
93 mRequestedFds.insertAt(requestedFd, 0);
94
95 RequestedCallback requestedCallback;
96 requestedCallback.callback = NULL;
Dianne Hackbornefa10852010-07-02 18:52:01 -070097 requestedCallback.looperCallback = NULL;
Dianne Hackborn45e0acb2010-09-07 15:28:30 -070098 requestedCallback.ident = 0;
Jeff Browne839a582010-04-22 18:58:52 -070099 requestedCallback.data = NULL;
100 mRequestedCallbacks.insertAt(requestedCallback, 0);
101}
102
103void PollLoop::closeWakePipe() {
104 close(mWakeReadPipeFd);
105 close(mWakeWritePipeFd);
106
107 // Note: We don't need to remove the poll structure or callback entry because this
108 // method is currently only called by the destructor.
109}
110
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700111int32_t PollLoop::pollOnce(int timeoutMillis, int* outEvents, void** outData) {
112 // If there are still pending fds from the last call, dispatch those
113 // first, to avoid an earlier fd from starving later ones.
114 const size_t pendingFdsCount = mPendingFds.size();
115 if (mPendingFdsPos < pendingFdsCount) {
116 const PendingCallback& pending = mPendingFds.itemAt(mPendingFdsPos);
117 mPendingFdsPos++;
118 if (outEvents != NULL) *outEvents = pending.events;
119 if (outData != NULL) *outData = pending.data;
Dianne Hackborn45e0acb2010-09-07 15:28:30 -0700120 return pending.ident;
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700121 }
122
Jeff Browne839a582010-04-22 18:58:52 -0700123 mLock.lock();
Jeff Brownf4a4ec22010-06-16 01:53:36 -0700124 while (mWaiters != 0) {
125 mResume.wait(mLock);
126 }
Jeff Browne839a582010-04-22 18:58:52 -0700127 mPolling = true;
128 mLock.unlock();
129
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700130 int32_t result;
Jeff Browne839a582010-04-22 18:58:52 -0700131 size_t requestedCount = mRequestedFds.size();
132
133#if DEBUG_POLL_AND_WAKE
134 LOGD("%p ~ pollOnce - waiting on %d fds", this, requestedCount);
135 for (size_t i = 0; i < requestedCount; i++) {
136 LOGD(" fd %d - events %d", mRequestedFds[i].fd, mRequestedFds[i].events);
137 }
138#endif
139
140 int respondedCount = poll(mRequestedFds.editArray(), requestedCount, timeoutMillis);
141
142 if (respondedCount == 0) {
143 // Timeout
144#if DEBUG_POLL_AND_WAKE
145 LOGD("%p ~ pollOnce - timeout", this);
146#endif
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700147 result = POLL_TIMEOUT;
Jeff Browne839a582010-04-22 18:58:52 -0700148 goto Done;
149 }
150
151 if (respondedCount < 0) {
152 // Error
153#if DEBUG_POLL_AND_WAKE
154 LOGD("%p ~ pollOnce - error, errno=%d", this, errno);
155#endif
156 if (errno != EINTR) {
157 LOGW("Poll failed with an unexpected error, errno=%d", errno);
158 }
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700159 result = POLL_ERROR;
Jeff Browne839a582010-04-22 18:58:52 -0700160 goto Done;
161 }
162
163#if DEBUG_POLL_AND_WAKE
164 LOGD("%p ~ pollOnce - handling responses from %d fds", this, respondedCount);
165 for (size_t i = 0; i < requestedCount; i++) {
166 LOGD(" fd %d - events %d, revents %d", mRequestedFds[i].fd, mRequestedFds[i].events,
167 mRequestedFds[i].revents);
168 }
169#endif
170
171 mPendingCallbacks.clear();
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700172 mPendingFds.clear();
173 mPendingFdsPos = 0;
174 if (outEvents != NULL) *outEvents = 0;
175 if (outData != NULL) *outData = NULL;
176
177 result = POLL_CALLBACK;
Jeff Browne839a582010-04-22 18:58:52 -0700178 for (size_t i = 0; i < requestedCount; i++) {
179 const struct pollfd& requestedFd = mRequestedFds.itemAt(i);
180
181 short revents = requestedFd.revents;
182 if (revents) {
183 const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700184 PendingCallback pending;
185 pending.fd = requestedFd.fd;
Dianne Hackborn45e0acb2010-09-07 15:28:30 -0700186 pending.ident = requestedCallback.ident;
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700187 pending.events = revents;
188 pending.callback = requestedCallback.callback;
189 pending.looperCallback = requestedCallback.looperCallback;
190 pending.data = requestedCallback.data;
Jeff Browne839a582010-04-22 18:58:52 -0700191
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700192 if (pending.callback || pending.looperCallback) {
193 mPendingCallbacks.push(pending);
194 } else if (pending.fd != mWakeReadPipeFd) {
195 if (result == POLL_CALLBACK) {
Dianne Hackborn45e0acb2010-09-07 15:28:30 -0700196 result = pending.ident;
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700197 if (outEvents != NULL) *outEvents = pending.events;
198 if (outData != NULL) *outData = pending.data;
Jeff Browne839a582010-04-22 18:58:52 -0700199 } else {
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700200 mPendingFds.push(pending);
Jeff Browne839a582010-04-22 18:58:52 -0700201 }
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700202 } else {
203#if DEBUG_POLL_AND_WAKE
204 LOGD("%p ~ pollOnce - awoken", this);
205#endif
206 char buffer[16];
207 ssize_t nRead;
208 do {
209 nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
210 } while (nRead == sizeof(buffer));
Jeff Browne839a582010-04-22 18:58:52 -0700211 }
212
213 respondedCount -= 1;
214 if (respondedCount == 0) {
215 break;
216 }
217 }
218 }
Jeff Browne839a582010-04-22 18:58:52 -0700219
220Done:
221 mLock.lock();
222 mPolling = false;
Jeff Brownf4a4ec22010-06-16 01:53:36 -0700223 if (mWaiters != 0) {
224 mAwake.broadcast();
225 }
Jeff Browne839a582010-04-22 18:58:52 -0700226 mLock.unlock();
227
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700228 if (result == POLL_CALLBACK || result >= 0) {
Jeff Browne839a582010-04-22 18:58:52 -0700229 size_t pendingCount = mPendingCallbacks.size();
230 for (size_t i = 0; i < pendingCount; i++) {
231 const PendingCallback& pendingCallback = mPendingCallbacks.itemAt(i);
232#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
233 LOGD("%p ~ pollOnce - invoking callback for fd %d", this, pendingCallback.fd);
234#endif
235
Dianne Hackbornefa10852010-07-02 18:52:01 -0700236 bool keep = true;
237 if (pendingCallback.callback != NULL) {
238 keep = pendingCallback.callback(pendingCallback.fd, pendingCallback.events,
239 pendingCallback.data);
240 } else {
241 keep = pendingCallback.looperCallback(pendingCallback.fd, pendingCallback.events,
242 pendingCallback.data) != 0;
243 }
Jeff Browne839a582010-04-22 18:58:52 -0700244 if (! keep) {
245 removeCallback(pendingCallback.fd);
246 }
247 }
248 }
249
250#if DEBUG_POLL_AND_WAKE
251 LOGD("%p ~ pollOnce - done", this);
252#endif
253 return result;
254}
255
256void PollLoop::wake() {
257#if DEBUG_POLL_AND_WAKE
258 LOGD("%p ~ wake", this);
259#endif
260
261 ssize_t nWrite = write(mWakeWritePipeFd, "W", 1);
262 if (nWrite != 1) {
263 if (errno != EAGAIN) {
264 LOGW("Could not write wake signal, errno=%d", errno);
265 }
266 }
267}
268
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700269bool PollLoop::getAllowNonCallbacks() const {
270 return mAllowNonCallbacks;
271}
272
Dianne Hackborn45e0acb2010-09-07 15:28:30 -0700273void PollLoop::setCallback(int fd, int ident, int events, Callback callback, void* data) {
274 setCallbackCommon(fd, ident, events, callback, NULL, data);
275}
276
Jeff Browne839a582010-04-22 18:58:52 -0700277void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
Dianne Hackborn45e0acb2010-09-07 15:28:30 -0700278 setCallbackCommon(fd, POLL_CALLBACK, events, callback, NULL, data);
Dianne Hackbornefa10852010-07-02 18:52:01 -0700279}
280
Dianne Hackborn45e0acb2010-09-07 15:28:30 -0700281void PollLoop::setLooperCallback(int fd, int ident, int events, ALooper_callbackFunc* callback,
Dianne Hackbornefa10852010-07-02 18:52:01 -0700282 void* data) {
Dianne Hackborn45e0acb2010-09-07 15:28:30 -0700283 setCallbackCommon(fd, ident, events, NULL, callback, data);
Dianne Hackbornefa10852010-07-02 18:52:01 -0700284}
285
Dianne Hackborn45e0acb2010-09-07 15:28:30 -0700286void PollLoop::setCallbackCommon(int fd, int ident, int events, Callback callback,
Dianne Hackbornefa10852010-07-02 18:52:01 -0700287 ALooper_callbackFunc* looperCallback, void* data) {
288
Jeff Browne839a582010-04-22 18:58:52 -0700289#if DEBUG_CALLBACKS
290 LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events);
291#endif
292
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700293 if (! events) {
294 LOGE("Invalid attempt to set a callback with no selected poll events.");
Jeff Browne839a582010-04-22 18:58:52 -0700295 removeCallback(fd);
296 return;
297 }
298
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700299 if (! callback && ! looperCallback && ! mAllowNonCallbacks) {
300 LOGE("Invalid attempt to set NULL callback but not allowed.");
301 removeCallback(fd);
302 return;
303 }
304
Jeff Browne839a582010-04-22 18:58:52 -0700305 wakeAndLock();
306
307 struct pollfd requestedFd;
308 requestedFd.fd = fd;
309 requestedFd.events = events;
310
311 RequestedCallback requestedCallback;
312 requestedCallback.callback = callback;
Dianne Hackbornefa10852010-07-02 18:52:01 -0700313 requestedCallback.looperCallback = looperCallback;
Dianne Hackborn45e0acb2010-09-07 15:28:30 -0700314 requestedCallback.ident = ident;
Jeff Browne839a582010-04-22 18:58:52 -0700315 requestedCallback.data = data;
316
317 ssize_t index = getRequestIndexLocked(fd);
318 if (index < 0) {
319 mRequestedFds.push(requestedFd);
320 mRequestedCallbacks.push(requestedCallback);
321 } else {
322 mRequestedFds.replaceAt(requestedFd, size_t(index));
323 mRequestedCallbacks.replaceAt(requestedCallback, size_t(index));
324 }
325
326 mLock.unlock();
327}
328
329bool PollLoop::removeCallback(int fd) {
330#if DEBUG_CALLBACKS
331 LOGD("%p ~ removeCallback - fd=%d", this, fd);
332#endif
333
334 wakeAndLock();
335
336 ssize_t index = getRequestIndexLocked(fd);
337 if (index >= 0) {
338 mRequestedFds.removeAt(size_t(index));
339 mRequestedCallbacks.removeAt(size_t(index));
340 }
341
342 mLock.unlock();
343 return index >= 0;
344}
345
346ssize_t PollLoop::getRequestIndexLocked(int fd) {
347 size_t requestCount = mRequestedFds.size();
348
349 for (size_t i = 0; i < requestCount; i++) {
350 if (mRequestedFds.itemAt(i).fd == fd) {
351 return i;
352 }
353 }
354
355 return -1;
356}
357
358void PollLoop::wakeAndLock() {
359 mLock.lock();
Jeff Brownf4a4ec22010-06-16 01:53:36 -0700360 mWaiters += 1;
Jeff Browne839a582010-04-22 18:58:52 -0700361 while (mPolling) {
362 wake();
363 mAwake.wait(mLock);
364 }
Jeff Brownf4a4ec22010-06-16 01:53:36 -0700365 mWaiters -= 1;
366 if (mWaiters == 0) {
367 mResume.signal();
368 }
Jeff Browne839a582010-04-22 18:58:52 -0700369}
370
371} // namespace android