blob: fe76cd08cef70deeaac9256bf6f45a7628ac2d0d [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 }
Jeff Browna665ca82010-09-08 11:49:43 -0700122
123 // Wait for wakeAndLock() waiters to run then set mPolling to true.
Jeff Browne839a582010-04-22 18:58:52 -0700124 mLock.lock();
Jeff Brownf4a4ec22010-06-16 01:53:36 -0700125 while (mWaiters != 0) {
126 mResume.wait(mLock);
127 }
Jeff Browne839a582010-04-22 18:58:52 -0700128 mPolling = true;
129 mLock.unlock();
130
Jeff Browna665ca82010-09-08 11:49:43 -0700131 // Poll.
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700132 int32_t result;
Jeff Browne839a582010-04-22 18:58:52 -0700133 size_t requestedCount = mRequestedFds.size();
134
135#if DEBUG_POLL_AND_WAKE
136 LOGD("%p ~ pollOnce - waiting on %d fds", this, requestedCount);
137 for (size_t i = 0; i < requestedCount; i++) {
138 LOGD(" fd %d - events %d", mRequestedFds[i].fd, mRequestedFds[i].events);
139 }
140#endif
141
142 int respondedCount = poll(mRequestedFds.editArray(), requestedCount, timeoutMillis);
143
144 if (respondedCount == 0) {
145 // Timeout
146#if DEBUG_POLL_AND_WAKE
147 LOGD("%p ~ pollOnce - timeout", this);
148#endif
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700149 result = POLL_TIMEOUT;
Jeff Browne839a582010-04-22 18:58:52 -0700150 goto Done;
151 }
152
153 if (respondedCount < 0) {
154 // Error
155#if DEBUG_POLL_AND_WAKE
156 LOGD("%p ~ pollOnce - error, errno=%d", this, errno);
157#endif
158 if (errno != EINTR) {
159 LOGW("Poll failed with an unexpected error, errno=%d", errno);
160 }
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700161 result = POLL_ERROR;
Jeff Browne839a582010-04-22 18:58:52 -0700162 goto Done;
163 }
164
165#if DEBUG_POLL_AND_WAKE
166 LOGD("%p ~ pollOnce - handling responses from %d fds", this, respondedCount);
167 for (size_t i = 0; i < requestedCount; i++) {
168 LOGD(" fd %d - events %d, revents %d", mRequestedFds[i].fd, mRequestedFds[i].events,
169 mRequestedFds[i].revents);
170 }
171#endif
172
Jeff Browna665ca82010-09-08 11:49:43 -0700173 // Process the poll results.
Jeff Browne839a582010-04-22 18:58:52 -0700174 mPendingCallbacks.clear();
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700175 mPendingFds.clear();
176 mPendingFdsPos = 0;
177 if (outEvents != NULL) *outEvents = 0;
178 if (outData != NULL) *outData = NULL;
179
180 result = POLL_CALLBACK;
Jeff Browne839a582010-04-22 18:58:52 -0700181 for (size_t i = 0; i < requestedCount; i++) {
182 const struct pollfd& requestedFd = mRequestedFds.itemAt(i);
183
184 short revents = requestedFd.revents;
185 if (revents) {
186 const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700187 PendingCallback pending;
188 pending.fd = requestedFd.fd;
Dianne Hackborn45e0acb2010-09-07 15:28:30 -0700189 pending.ident = requestedCallback.ident;
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700190 pending.events = revents;
191 pending.callback = requestedCallback.callback;
192 pending.looperCallback = requestedCallback.looperCallback;
193 pending.data = requestedCallback.data;
Jeff Browne839a582010-04-22 18:58:52 -0700194
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700195 if (pending.callback || pending.looperCallback) {
196 mPendingCallbacks.push(pending);
197 } else if (pending.fd != mWakeReadPipeFd) {
198 if (result == POLL_CALLBACK) {
Dianne Hackborn45e0acb2010-09-07 15:28:30 -0700199 result = pending.ident;
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700200 if (outEvents != NULL) *outEvents = pending.events;
201 if (outData != NULL) *outData = pending.data;
Jeff Browne839a582010-04-22 18:58:52 -0700202 } else {
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700203 mPendingFds.push(pending);
Jeff Browne839a582010-04-22 18:58:52 -0700204 }
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700205 } else {
206#if DEBUG_POLL_AND_WAKE
207 LOGD("%p ~ pollOnce - awoken", this);
208#endif
209 char buffer[16];
210 ssize_t nRead;
211 do {
212 nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
213 } while (nRead == sizeof(buffer));
Jeff Browne839a582010-04-22 18:58:52 -0700214 }
215
216 respondedCount -= 1;
217 if (respondedCount == 0) {
218 break;
219 }
220 }
221 }
Jeff Browne839a582010-04-22 18:58:52 -0700222
223Done:
Jeff Browna665ca82010-09-08 11:49:43 -0700224 // Set mPolling to false and wake up the wakeAndLock() waiters.
Jeff Browne839a582010-04-22 18:58:52 -0700225 mLock.lock();
226 mPolling = false;
Jeff Brownf4a4ec22010-06-16 01:53:36 -0700227 if (mWaiters != 0) {
228 mAwake.broadcast();
229 }
Jeff Browne839a582010-04-22 18:58:52 -0700230 mLock.unlock();
231
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700232 if (result == POLL_CALLBACK || result >= 0) {
Jeff Browne839a582010-04-22 18:58:52 -0700233 size_t pendingCount = mPendingCallbacks.size();
234 for (size_t i = 0; i < pendingCount; i++) {
235 const PendingCallback& pendingCallback = mPendingCallbacks.itemAt(i);
236#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
237 LOGD("%p ~ pollOnce - invoking callback for fd %d", this, pendingCallback.fd);
238#endif
239
Dianne Hackbornefa10852010-07-02 18:52:01 -0700240 bool keep = true;
241 if (pendingCallback.callback != NULL) {
242 keep = pendingCallback.callback(pendingCallback.fd, pendingCallback.events,
243 pendingCallback.data);
244 } else {
245 keep = pendingCallback.looperCallback(pendingCallback.fd, pendingCallback.events,
246 pendingCallback.data) != 0;
247 }
Jeff Browne839a582010-04-22 18:58:52 -0700248 if (! keep) {
249 removeCallback(pendingCallback.fd);
250 }
251 }
252 }
253
254#if DEBUG_POLL_AND_WAKE
255 LOGD("%p ~ pollOnce - done", this);
256#endif
257 return result;
258}
259
260void PollLoop::wake() {
261#if DEBUG_POLL_AND_WAKE
262 LOGD("%p ~ wake", this);
263#endif
264
265 ssize_t nWrite = write(mWakeWritePipeFd, "W", 1);
266 if (nWrite != 1) {
267 if (errno != EAGAIN) {
268 LOGW("Could not write wake signal, errno=%d", errno);
269 }
270 }
271}
272
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700273bool PollLoop::getAllowNonCallbacks() const {
274 return mAllowNonCallbacks;
275}
276
Dianne Hackborn45e0acb2010-09-07 15:28:30 -0700277void PollLoop::setCallback(int fd, int ident, int events, Callback callback, void* data) {
278 setCallbackCommon(fd, ident, events, callback, NULL, data);
279}
280
Jeff Browne839a582010-04-22 18:58:52 -0700281void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
Dianne Hackborn45e0acb2010-09-07 15:28:30 -0700282 setCallbackCommon(fd, POLL_CALLBACK, events, callback, NULL, data);
Dianne Hackbornefa10852010-07-02 18:52:01 -0700283}
284
Dianne Hackborn45e0acb2010-09-07 15:28:30 -0700285void PollLoop::setLooperCallback(int fd, int ident, int events, ALooper_callbackFunc* callback,
Dianne Hackbornefa10852010-07-02 18:52:01 -0700286 void* data) {
Dianne Hackborn45e0acb2010-09-07 15:28:30 -0700287 setCallbackCommon(fd, ident, events, NULL, callback, data);
Dianne Hackbornefa10852010-07-02 18:52:01 -0700288}
289
Dianne Hackborn45e0acb2010-09-07 15:28:30 -0700290void PollLoop::setCallbackCommon(int fd, int ident, int events, Callback callback,
Dianne Hackbornefa10852010-07-02 18:52:01 -0700291 ALooper_callbackFunc* looperCallback, void* data) {
292
Jeff Browne839a582010-04-22 18:58:52 -0700293#if DEBUG_CALLBACKS
294 LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events);
295#endif
296
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700297 if (! events) {
298 LOGE("Invalid attempt to set a callback with no selected poll events.");
Jeff Browne839a582010-04-22 18:58:52 -0700299 removeCallback(fd);
300 return;
301 }
302
Dianne Hackborn3c5d1252010-07-07 14:27:31 -0700303 if (! callback && ! looperCallback && ! mAllowNonCallbacks) {
304 LOGE("Invalid attempt to set NULL callback but not allowed.");
305 removeCallback(fd);
306 return;
307 }
308
Jeff Browne839a582010-04-22 18:58:52 -0700309 wakeAndLock();
310
311 struct pollfd requestedFd;
312 requestedFd.fd = fd;
313 requestedFd.events = events;
314
315 RequestedCallback requestedCallback;
316 requestedCallback.callback = callback;
Dianne Hackbornefa10852010-07-02 18:52:01 -0700317 requestedCallback.looperCallback = looperCallback;
Dianne Hackborn45e0acb2010-09-07 15:28:30 -0700318 requestedCallback.ident = ident;
Jeff Browne839a582010-04-22 18:58:52 -0700319 requestedCallback.data = data;
320
321 ssize_t index = getRequestIndexLocked(fd);
322 if (index < 0) {
323 mRequestedFds.push(requestedFd);
324 mRequestedCallbacks.push(requestedCallback);
325 } else {
326 mRequestedFds.replaceAt(requestedFd, size_t(index));
327 mRequestedCallbacks.replaceAt(requestedCallback, size_t(index));
328 }
329
330 mLock.unlock();
331}
332
333bool PollLoop::removeCallback(int fd) {
334#if DEBUG_CALLBACKS
335 LOGD("%p ~ removeCallback - fd=%d", this, fd);
336#endif
337
338 wakeAndLock();
339
340 ssize_t index = getRequestIndexLocked(fd);
341 if (index >= 0) {
342 mRequestedFds.removeAt(size_t(index));
343 mRequestedCallbacks.removeAt(size_t(index));
344 }
345
346 mLock.unlock();
347 return index >= 0;
348}
349
350ssize_t PollLoop::getRequestIndexLocked(int fd) {
351 size_t requestCount = mRequestedFds.size();
352
353 for (size_t i = 0; i < requestCount; i++) {
354 if (mRequestedFds.itemAt(i).fd == fd) {
355 return i;
356 }
357 }
358
359 return -1;
360}
361
362void PollLoop::wakeAndLock() {
363 mLock.lock();
Jeff Browna665ca82010-09-08 11:49:43 -0700364
Jeff Brownf4a4ec22010-06-16 01:53:36 -0700365 mWaiters += 1;
Jeff Browne839a582010-04-22 18:58:52 -0700366 while (mPolling) {
367 wake();
368 mAwake.wait(mLock);
369 }
Jeff Browna665ca82010-09-08 11:49:43 -0700370
Jeff Brownf4a4ec22010-06-16 01:53:36 -0700371 mWaiters -= 1;
372 if (mWaiters == 0) {
373 mResume.signal();
374 }
Jeff Browne839a582010-04-22 18:58:52 -0700375}
376
377} // namespace android