blob: b54fb9dd7353cdfae47cf265b4b2ba31efa601c1 [file] [log] [blame]
Jeff Brown4fe6c3e2010-09-13 23:17:30 -07001//
2// Copyright 2010 The Android Open Source Project
3//
4// A looper implementation based on epoll().
5//
6#define LOG_TAG "Looper"
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.
14#define DEBUG_CALLBACKS 0
15
16#include <cutils/log.h>
17#include <utils/Looper.h>
18#include <utils/Timers.h>
19
20#include <unistd.h>
21#include <fcntl.h>
Jeff Brown05dc66a2011-03-02 14:41:58 -080022#include <limits.h>
Jeff Brown4fe6c3e2010-09-13 23:17:30 -070023
24
25namespace android {
26
Jeff Brown05dc66a2011-03-02 14:41:58 -080027// --- WeakMessageHandler ---
28
29WeakMessageHandler::WeakMessageHandler(const wp<MessageHandler>& handler) :
30 mHandler(handler) {
31}
32
33void WeakMessageHandler::handleMessage(const Message& message) {
34 sp<MessageHandler> handler = mHandler.promote();
35 if (handler != NULL) {
36 handler->handleMessage(message);
37 }
38}
39
40
41// --- Looper ---
42
Jeff Brown415d8c32010-10-05 15:35:37 -070043#ifdef LOOPER_USES_EPOLL
Jeff Brown4fe6c3e2010-09-13 23:17:30 -070044// Hint for number of file descriptors to be associated with the epoll instance.
45static const int EPOLL_SIZE_HINT = 8;
46
47// Maximum number of file descriptors for which to retrieve poll events each iteration.
48static const int EPOLL_MAX_EVENTS = 16;
Jeff Brown415d8c32010-10-05 15:35:37 -070049#endif
Jeff Brown4fe6c3e2010-09-13 23:17:30 -070050
Jeff Brown134b4ae2010-09-21 15:11:18 -070051static pthread_once_t gTLSOnce = PTHREAD_ONCE_INIT;
52static pthread_key_t gTLSKey = 0;
53
Jeff Brown4fe6c3e2010-09-13 23:17:30 -070054Looper::Looper(bool allowNonCallbacks) :
Jeff Brown05dc66a2011-03-02 14:41:58 -080055 mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
56 mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
Jeff Brown4fe6c3e2010-09-13 23:17:30 -070057 int wakeFds[2];
58 int result = pipe(wakeFds);
59 LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
60
61 mWakeReadPipeFd = wakeFds[0];
62 mWakeWritePipeFd = wakeFds[1];
63
64 result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
65 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
66 errno);
67
68 result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
69 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
70 errno);
71
Jeff Brown415d8c32010-10-05 15:35:37 -070072#ifdef LOOPER_USES_EPOLL
73 // Allocate the epoll instance and register the wake pipe.
74 mEpollFd = epoll_create(EPOLL_SIZE_HINT);
75 LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
76
Jeff Brown4fe6c3e2010-09-13 23:17:30 -070077 struct epoll_event eventItem;
Jeff Brown134b4ae2010-09-21 15:11:18 -070078 memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
Jeff Brown4fe6c3e2010-09-13 23:17:30 -070079 eventItem.events = EPOLLIN;
80 eventItem.data.fd = mWakeReadPipeFd;
81 result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
82 LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
83 errno);
Jeff Brown415d8c32010-10-05 15:35:37 -070084#else
85 // Add the wake pipe to the head of the request list with a null callback.
86 struct pollfd requestedFd;
87 requestedFd.fd = mWakeReadPipeFd;
88 requestedFd.events = POLLIN;
89 mRequestedFds.push(requestedFd);
90
91 Request request;
92 request.fd = mWakeReadPipeFd;
93 request.callback = NULL;
94 request.ident = 0;
95 request.data = NULL;
96 mRequests.push(request);
97
98 mPolling = false;
99 mWaiters = 0;
100#endif
101
102#ifdef LOOPER_STATISTICS
103 mPendingWakeTime = -1;
104 mPendingWakeCount = 0;
105 mSampledWakeCycles = 0;
106 mSampledWakeCountSum = 0;
107 mSampledWakeLatencySum = 0;
108
109 mSampledPolls = 0;
110 mSampledZeroPollCount = 0;
111 mSampledZeroPollLatencySum = 0;
112 mSampledTimeoutPollCount = 0;
113 mSampledTimeoutPollLatencySum = 0;
114#endif
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700115}
116
117Looper::~Looper() {
118 close(mWakeReadPipeFd);
119 close(mWakeWritePipeFd);
Jeff Brown415d8c32010-10-05 15:35:37 -0700120#ifdef LOOPER_USES_EPOLL
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700121 close(mEpollFd);
Jeff Brown415d8c32010-10-05 15:35:37 -0700122#endif
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700123}
124
Jeff Brown134b4ae2010-09-21 15:11:18 -0700125void Looper::initTLSKey() {
126 int result = pthread_key_create(& gTLSKey, threadDestructor);
127 LOG_ALWAYS_FATAL_IF(result != 0, "Could not allocate TLS key.");
128}
129
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700130void Looper::threadDestructor(void *st) {
131 Looper* const self = static_cast<Looper*>(st);
132 if (self != NULL) {
133 self->decStrong((void*)threadDestructor);
134 }
135}
136
137void Looper::setForThread(const sp<Looper>& looper) {
138 sp<Looper> old = getForThread(); // also has side-effect of initializing TLS
139
140 if (looper != NULL) {
141 looper->incStrong((void*)threadDestructor);
142 }
143
Jeff Brown134b4ae2010-09-21 15:11:18 -0700144 pthread_setspecific(gTLSKey, looper.get());
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700145
146 if (old != NULL) {
147 old->decStrong((void*)threadDestructor);
148 }
149}
150
151sp<Looper> Looper::getForThread() {
Jeff Brown134b4ae2010-09-21 15:11:18 -0700152 int result = pthread_once(& gTLSOnce, initTLSKey);
153 LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed");
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700154
Jeff Brown134b4ae2010-09-21 15:11:18 -0700155 return (Looper*)pthread_getspecific(gTLSKey);
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700156}
157
158sp<Looper> Looper::prepare(int opts) {
159 bool allowNonCallbacks = opts & ALOOPER_PREPARE_ALLOW_NON_CALLBACKS;
160 sp<Looper> looper = Looper::getForThread();
161 if (looper == NULL) {
162 looper = new Looper(allowNonCallbacks);
163 Looper::setForThread(looper);
164 }
165 if (looper->getAllowNonCallbacks() != allowNonCallbacks) {
166 LOGW("Looper already prepared for this thread with a different value for the "
167 "ALOOPER_PREPARE_ALLOW_NON_CALLBACKS option.");
168 }
169 return looper;
170}
171
172bool Looper::getAllowNonCallbacks() const {
173 return mAllowNonCallbacks;
174}
175
176int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
177 int result = 0;
178 for (;;) {
179 while (mResponseIndex < mResponses.size()) {
180 const Response& response = mResponses.itemAt(mResponseIndex++);
Jeff Brown05dc66a2011-03-02 14:41:58 -0800181 ALooper_callbackFunc callback = response.request.callback;
182 if (!callback) {
183 int ident = response.request.ident;
184 int fd = response.request.fd;
185 int events = response.events;
186 void* data = response.request.data;
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700187#if DEBUG_POLL_AND_WAKE
188 LOGD("%p ~ pollOnce - returning signalled identifier %d: "
Jeff Brown05dc66a2011-03-02 14:41:58 -0800189 "fd=%d, events=0x%x, data=%p",
190 this, ident, fd, events, data);
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700191#endif
Jeff Brown05dc66a2011-03-02 14:41:58 -0800192 if (outFd != NULL) *outFd = fd;
193 if (outEvents != NULL) *outEvents = events;
194 if (outData != NULL) *outData = data;
195 return ident;
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700196 }
197 }
198
199 if (result != 0) {
200#if DEBUG_POLL_AND_WAKE
201 LOGD("%p ~ pollOnce - returning result %d", this, result);
202#endif
203 if (outFd != NULL) *outFd = 0;
204 if (outEvents != NULL) *outEvents = NULL;
205 if (outData != NULL) *outData = NULL;
206 return result;
207 }
208
209 result = pollInner(timeoutMillis);
210 }
211}
212
213int Looper::pollInner(int timeoutMillis) {
214#if DEBUG_POLL_AND_WAKE
215 LOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
216#endif
Jeff Brown415d8c32010-10-05 15:35:37 -0700217
Jeff Brown05dc66a2011-03-02 14:41:58 -0800218 // Adjust the timeout based on when the next message is due.
219 if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
220 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
Jeff Brownaa3855d2011-03-17 01:34:19 -0700221 int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
222 if (messageTimeoutMillis >= 0
223 && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
224 timeoutMillis = messageTimeoutMillis;
Jeff Brown05dc66a2011-03-02 14:41:58 -0800225 }
226#if DEBUG_POLL_AND_WAKE
227 LOGD("%p ~ pollOnce - next message in %lldns, adjusted timeout: timeoutMillis=%d",
228 this, mNextMessageUptime - now, timeoutMillis);
229#endif
230 }
231
232 // Poll.
Jeff Brown415d8c32010-10-05 15:35:37 -0700233 int result = ALOOPER_POLL_WAKE;
234 mResponses.clear();
235 mResponseIndex = 0;
236
237#ifdef LOOPER_STATISTICS
238 nsecs_t pollStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
239#endif
240
241#ifdef LOOPER_USES_EPOLL
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700242 struct epoll_event eventItems[EPOLL_MAX_EVENTS];
243 int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
Jeff Brown415d8c32010-10-05 15:35:37 -0700244#else
245 // Wait for wakeAndLock() waiters to run then set mPolling to true.
246 mLock.lock();
247 while (mWaiters != 0) {
248 mResume.wait(mLock);
249 }
250 mPolling = true;
251 mLock.unlock();
252
253 size_t requestedCount = mRequestedFds.size();
254 int eventCount = poll(mRequestedFds.editArray(), requestedCount, timeoutMillis);
255#endif
256
Jeff Brown05dc66a2011-03-02 14:41:58 -0800257 // Acquire lock.
258 mLock.lock();
259
260 // Check for poll error.
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700261 if (eventCount < 0) {
Jeff Brown7dae0e42010-09-16 17:04:52 -0700262 if (errno == EINTR) {
Jeff Brown415d8c32010-10-05 15:35:37 -0700263 goto Done;
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700264 }
Jeff Brown7dae0e42010-09-16 17:04:52 -0700265 LOGW("Poll failed with an unexpected error, errno=%d", errno);
Jeff Brown415d8c32010-10-05 15:35:37 -0700266 result = ALOOPER_POLL_ERROR;
267 goto Done;
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700268 }
269
Jeff Brown05dc66a2011-03-02 14:41:58 -0800270 // Check for poll timeout.
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700271 if (eventCount == 0) {
272#if DEBUG_POLL_AND_WAKE
273 LOGD("%p ~ pollOnce - timeout", this);
274#endif
Jeff Brown415d8c32010-10-05 15:35:37 -0700275 result = ALOOPER_POLL_TIMEOUT;
276 goto Done;
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700277 }
278
Jeff Brown05dc66a2011-03-02 14:41:58 -0800279 // Handle all events.
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700280#if DEBUG_POLL_AND_WAKE
281 LOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
282#endif
Jeff Brown415d8c32010-10-05 15:35:37 -0700283
284#ifdef LOOPER_USES_EPOLL
Jeff Brown96049872010-09-17 17:01:23 -0700285 for (int i = 0; i < eventCount; i++) {
286 int fd = eventItems[i].data.fd;
287 uint32_t epollEvents = eventItems[i].events;
288 if (fd == mWakeReadPipeFd) {
289 if (epollEvents & EPOLLIN) {
Jeff Brown415d8c32010-10-05 15:35:37 -0700290 awoken();
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700291 } else {
Jeff Brown96049872010-09-17 17:01:23 -0700292 LOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
293 }
294 } else {
Jeff Brown96049872010-09-17 17:01:23 -0700295 ssize_t requestIndex = mRequests.indexOfKey(fd);
296 if (requestIndex >= 0) {
297 int events = 0;
298 if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;
299 if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;
300 if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;
301 if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;
Jeff Brown415d8c32010-10-05 15:35:37 -0700302 pushResponse(events, mRequests.valueAt(requestIndex));
Jeff Brown96049872010-09-17 17:01:23 -0700303 } else {
304 LOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
305 "no longer registered.", epollEvents, fd);
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700306 }
307 }
308 }
Jeff Brown415d8c32010-10-05 15:35:37 -0700309Done: ;
310#else
311 for (size_t i = 0; i < requestedCount; i++) {
312 const struct pollfd& requestedFd = mRequestedFds.itemAt(i);
313
314 short pollEvents = requestedFd.revents;
315 if (pollEvents) {
316 if (requestedFd.fd == mWakeReadPipeFd) {
317 if (pollEvents & POLLIN) {
318 awoken();
319 } else {
320 LOGW("Ignoring unexpected poll events 0x%x on wake read pipe.", pollEvents);
321 }
322 } else {
323 int events = 0;
324 if (pollEvents & POLLIN) events |= ALOOPER_EVENT_INPUT;
325 if (pollEvents & POLLOUT) events |= ALOOPER_EVENT_OUTPUT;
326 if (pollEvents & POLLERR) events |= ALOOPER_EVENT_ERROR;
327 if (pollEvents & POLLHUP) events |= ALOOPER_EVENT_HANGUP;
328 if (pollEvents & POLLNVAL) events |= ALOOPER_EVENT_INVALID;
329 pushResponse(events, mRequests.itemAt(i));
330 }
331 if (--eventCount == 0) {
332 break;
333 }
334 }
335 }
Jeff Brown415d8c32010-10-05 15:35:37 -0700336Done:
337 // Set mPolling to false and wake up the wakeAndLock() waiters.
Jeff Brown415d8c32010-10-05 15:35:37 -0700338 mPolling = false;
339 if (mWaiters != 0) {
340 mAwake.broadcast();
341 }
Jeff Brown415d8c32010-10-05 15:35:37 -0700342#endif
343
344#ifdef LOOPER_STATISTICS
345 nsecs_t pollEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
346 mSampledPolls += 1;
347 if (timeoutMillis == 0) {
348 mSampledZeroPollCount += 1;
349 mSampledZeroPollLatencySum += pollEndTime - pollStartTime;
350 } else if (timeoutMillis > 0 && result == ALOOPER_POLL_TIMEOUT) {
351 mSampledTimeoutPollCount += 1;
352 mSampledTimeoutPollLatencySum += pollEndTime - pollStartTime
353 - milliseconds_to_nanoseconds(timeoutMillis);
354 }
355 if (mSampledPolls == SAMPLED_POLLS_TO_AGGREGATE) {
356 LOGD("%p ~ poll latency statistics: %0.3fms zero timeout, %0.3fms non-zero timeout", this,
357 0.000001f * float(mSampledZeroPollLatencySum) / mSampledZeroPollCount,
358 0.000001f * float(mSampledTimeoutPollLatencySum) / mSampledTimeoutPollCount);
359 mSampledPolls = 0;
360 mSampledZeroPollCount = 0;
361 mSampledZeroPollLatencySum = 0;
362 mSampledTimeoutPollCount = 0;
363 mSampledTimeoutPollLatencySum = 0;
364 }
365#endif
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700366
Jeff Brown05dc66a2011-03-02 14:41:58 -0800367 // Invoke pending message callbacks.
368 mNextMessageUptime = LLONG_MAX;
369 while (mMessageEnvelopes.size() != 0) {
370 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
371 const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
372 if (messageEnvelope.uptime <= now) {
373 // Remove the envelope from the list.
374 // We keep a strong reference to the handler until the call to handleMessage
375 // finishes. Then we drop it so that the handler can be deleted *before*
376 // we reacquire our lock.
377 { // obtain handler
378 sp<MessageHandler> handler = messageEnvelope.handler;
379 Message message = messageEnvelope.message;
380 mMessageEnvelopes.removeAt(0);
381 mSendingMessage = true;
382 mLock.unlock();
383
384#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
385 LOGD("%p ~ pollOnce - sending message: handler=%p, what=%d",
386 this, handler.get(), message.what);
387#endif
388 handler->handleMessage(message);
389 } // release handler
390
391 mLock.lock();
392 mSendingMessage = false;
393 result = ALOOPER_POLL_CALLBACK;
394 } else {
395 // The last message left at the head of the queue determines the next wakeup time.
396 mNextMessageUptime = messageEnvelope.uptime;
397 break;
398 }
399 }
400
401 // Release lock.
402 mLock.unlock();
403
404 // Invoke all response callbacks.
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700405 for (size_t i = 0; i < mResponses.size(); i++) {
406 const Response& response = mResponses.itemAt(i);
Jeff Brown05dc66a2011-03-02 14:41:58 -0800407 ALooper_callbackFunc callback = response.request.callback;
408 if (callback) {
409 int fd = response.request.fd;
410 int events = response.events;
411 void* data = response.request.data;
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700412#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
Jeff Brown05dc66a2011-03-02 14:41:58 -0800413 LOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",
414 this, callback, fd, events, data);
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700415#endif
Jeff Brown05dc66a2011-03-02 14:41:58 -0800416 int callbackResult = callback(fd, events, data);
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700417 if (callbackResult == 0) {
Jeff Brown05dc66a2011-03-02 14:41:58 -0800418 removeFd(fd);
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700419 }
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700420 result = ALOOPER_POLL_CALLBACK;
421 }
422 }
423 return result;
424}
425
426int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
427 if (timeoutMillis <= 0) {
428 int result;
429 do {
430 result = pollOnce(timeoutMillis, outFd, outEvents, outData);
431 } while (result == ALOOPER_POLL_CALLBACK);
432 return result;
433 } else {
434 nsecs_t endTime = systemTime(SYSTEM_TIME_MONOTONIC)
435 + milliseconds_to_nanoseconds(timeoutMillis);
436
437 for (;;) {
438 int result = pollOnce(timeoutMillis, outFd, outEvents, outData);
439 if (result != ALOOPER_POLL_CALLBACK) {
440 return result;
441 }
442
Jeff Brownaa3855d2011-03-17 01:34:19 -0700443 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
444 timeoutMillis = toMillisecondTimeoutDelay(now, endTime);
445 if (timeoutMillis == 0) {
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700446 return ALOOPER_POLL_TIMEOUT;
447 }
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700448 }
449 }
450}
451
452void Looper::wake() {
453#if DEBUG_POLL_AND_WAKE
454 LOGD("%p ~ wake", this);
455#endif
456
Jeff Brown415d8c32010-10-05 15:35:37 -0700457#ifdef LOOPER_STATISTICS
458 // FIXME: Possible race with awoken() but this code is for testing only and is rarely enabled.
459 if (mPendingWakeCount++ == 0) {
460 mPendingWakeTime = systemTime(SYSTEM_TIME_MONOTONIC);
461 }
462#endif
463
Jeff Brown7dae0e42010-09-16 17:04:52 -0700464 ssize_t nWrite;
465 do {
466 nWrite = write(mWakeWritePipeFd, "W", 1);
467 } while (nWrite == -1 && errno == EINTR);
468
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700469 if (nWrite != 1) {
470 if (errno != EAGAIN) {
471 LOGW("Could not write wake signal, errno=%d", errno);
472 }
473 }
474}
475
Jeff Brown415d8c32010-10-05 15:35:37 -0700476void Looper::awoken() {
477#if DEBUG_POLL_AND_WAKE
478 LOGD("%p ~ awoken", this);
479#endif
480
481#ifdef LOOPER_STATISTICS
482 if (mPendingWakeCount == 0) {
483 LOGD("%p ~ awoken: spurious!", this);
484 } else {
485 mSampledWakeCycles += 1;
486 mSampledWakeCountSum += mPendingWakeCount;
487 mSampledWakeLatencySum += systemTime(SYSTEM_TIME_MONOTONIC) - mPendingWakeTime;
488 mPendingWakeCount = 0;
489 mPendingWakeTime = -1;
490 if (mSampledWakeCycles == SAMPLED_WAKE_CYCLES_TO_AGGREGATE) {
491 LOGD("%p ~ wake statistics: %0.3fms wake latency, %0.3f wakes per cycle", this,
492 0.000001f * float(mSampledWakeLatencySum) / mSampledWakeCycles,
493 float(mSampledWakeCountSum) / mSampledWakeCycles);
494 mSampledWakeCycles = 0;
495 mSampledWakeCountSum = 0;
496 mSampledWakeLatencySum = 0;
497 }
498 }
499#endif
500
501 char buffer[16];
502 ssize_t nRead;
503 do {
504 nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
505 } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
506}
507
508void Looper::pushResponse(int events, const Request& request) {
509 Response response;
510 response.events = events;
511 response.request = request;
512 mResponses.push(response);
513}
514
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700515int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) {
516#if DEBUG_CALLBACKS
517 LOGD("%p ~ addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident,
518 events, callback, data);
519#endif
520
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700521 if (! callback) {
522 if (! mAllowNonCallbacks) {
523 LOGE("Invalid attempt to set NULL callback but not allowed for this looper.");
524 return -1;
525 }
526
527 if (ident < 0) {
528 LOGE("Invalid attempt to set NULL callback with ident <= 0.");
529 return -1;
530 }
531 }
532
Jeff Brown415d8c32010-10-05 15:35:37 -0700533#ifdef LOOPER_USES_EPOLL
534 int epollEvents = 0;
535 if (events & ALOOPER_EVENT_INPUT) epollEvents |= EPOLLIN;
536 if (events & ALOOPER_EVENT_OUTPUT) epollEvents |= EPOLLOUT;
537
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700538 { // acquire lock
539 AutoMutex _l(mLock);
540
541 Request request;
542 request.fd = fd;
543 request.ident = ident;
544 request.callback = callback;
545 request.data = data;
546
547 struct epoll_event eventItem;
Jeff Brown134b4ae2010-09-21 15:11:18 -0700548 memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700549 eventItem.events = epollEvents;
550 eventItem.data.fd = fd;
551
552 ssize_t requestIndex = mRequests.indexOfKey(fd);
553 if (requestIndex < 0) {
554 int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
555 if (epollResult < 0) {
556 LOGE("Error adding epoll events for fd %d, errno=%d", fd, errno);
557 return -1;
558 }
559 mRequests.add(fd, request);
560 } else {
561 int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
562 if (epollResult < 0) {
563 LOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno);
564 return -1;
565 }
566 mRequests.replaceValueAt(requestIndex, request);
567 }
568 } // release lock
Jeff Brown415d8c32010-10-05 15:35:37 -0700569#else
570 int pollEvents = 0;
571 if (events & ALOOPER_EVENT_INPUT) pollEvents |= POLLIN;
572 if (events & ALOOPER_EVENT_OUTPUT) pollEvents |= POLLOUT;
573
574 wakeAndLock(); // acquire lock
575
576 struct pollfd requestedFd;
577 requestedFd.fd = fd;
578 requestedFd.events = pollEvents;
579
580 Request request;
581 request.fd = fd;
582 request.ident = ident;
583 request.callback = callback;
584 request.data = data;
585 ssize_t index = getRequestIndexLocked(fd);
586 if (index < 0) {
587 mRequestedFds.push(requestedFd);
588 mRequests.push(request);
589 } else {
590 mRequestedFds.replaceAt(requestedFd, size_t(index));
591 mRequests.replaceAt(request, size_t(index));
592 }
593
594 mLock.unlock(); // release lock
595#endif
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700596 return 1;
597}
598
599int Looper::removeFd(int fd) {
600#if DEBUG_CALLBACKS
601 LOGD("%p ~ removeFd - fd=%d", this, fd);
602#endif
603
Jeff Brown415d8c32010-10-05 15:35:37 -0700604#ifdef LOOPER_USES_EPOLL
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700605 { // acquire lock
606 AutoMutex _l(mLock);
607 ssize_t requestIndex = mRequests.indexOfKey(fd);
608 if (requestIndex < 0) {
609 return 0;
610 }
611
612 int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
613 if (epollResult < 0) {
614 LOGE("Error removing epoll events for fd %d, errno=%d", fd, errno);
615 return -1;
616 }
617
618 mRequests.removeItemsAt(requestIndex);
Jeff Brown415d8c32010-10-05 15:35:37 -0700619 } // release lock
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700620 return 1;
Jeff Brown415d8c32010-10-05 15:35:37 -0700621#else
622 wakeAndLock(); // acquire lock
623
624 ssize_t index = getRequestIndexLocked(fd);
625 if (index >= 0) {
626 mRequestedFds.removeAt(size_t(index));
627 mRequests.removeAt(size_t(index));
628 }
629
630 mLock.unlock(); // release lock
631 return index >= 0;
632#endif
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700633}
634
Jeff Brown415d8c32010-10-05 15:35:37 -0700635#ifndef LOOPER_USES_EPOLL
636ssize_t Looper::getRequestIndexLocked(int fd) {
637 size_t requestCount = mRequestedFds.size();
638
639 for (size_t i = 0; i < requestCount; i++) {
640 if (mRequestedFds.itemAt(i).fd == fd) {
641 return i;
642 }
643 }
644
645 return -1;
646}
647
648void Looper::wakeAndLock() {
649 mLock.lock();
650
651 mWaiters += 1;
652 while (mPolling) {
653 wake();
654 mAwake.wait(mLock);
655 }
656
657 mWaiters -= 1;
658 if (mWaiters == 0) {
659 mResume.signal();
660 }
661}
662#endif
663
Jeff Brown05dc66a2011-03-02 14:41:58 -0800664void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
Jeff Brown2352b972011-04-12 22:39:53 -0700665 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
666 sendMessageAtTime(now, handler, message);
Jeff Brown05dc66a2011-03-02 14:41:58 -0800667}
668
669void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
670 const Message& message) {
671 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
672 sendMessageAtTime(now + uptimeDelay, handler, message);
673}
674
675void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
676 const Message& message) {
677#if DEBUG_CALLBACKS
678 LOGD("%p ~ sendMessageAtTime - uptime=%lld, handler=%p, what=%d",
679 this, uptime, handler.get(), message.what);
680#endif
681
682 size_t i = 0;
683 { // acquire lock
684 AutoMutex _l(mLock);
685
686 size_t messageCount = mMessageEnvelopes.size();
687 while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) {
688 i += 1;
689 }
690
691 MessageEnvelope messageEnvelope(uptime, handler, message);
692 mMessageEnvelopes.insertAt(messageEnvelope, i, 1);
693
694 // Optimization: If the Looper is currently sending a message, then we can skip
695 // the call to wake() because the next thing the Looper will do after processing
696 // messages is to decide when the next wakeup time should be. In fact, it does
697 // not even matter whether this code is running on the Looper thread.
698 if (mSendingMessage) {
699 return;
700 }
701 } // release lock
702
703 // Wake the poll loop only when we enqueue a new message at the head.
704 if (i == 0) {
705 wake();
706 }
707}
708
709void Looper::removeMessages(const sp<MessageHandler>& handler) {
710#if DEBUG_CALLBACKS
711 LOGD("%p ~ removeMessages - handler=%p", this, handler.get());
712#endif
713
714 { // acquire lock
715 AutoMutex _l(mLock);
716
717 for (size_t i = mMessageEnvelopes.size(); i != 0; ) {
718 const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(--i);
719 if (messageEnvelope.handler == handler) {
720 mMessageEnvelopes.removeAt(i);
721 }
722 }
723 } // release lock
724}
725
726void Looper::removeMessages(const sp<MessageHandler>& handler, int what) {
727#if DEBUG_CALLBACKS
728 LOGD("%p ~ removeMessages - handler=%p, what=%d", this, handler.get(), what);
729#endif
730
731 { // acquire lock
732 AutoMutex _l(mLock);
733
734 for (size_t i = mMessageEnvelopes.size(); i != 0; ) {
735 const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(--i);
736 if (messageEnvelope.handler == handler
737 && messageEnvelope.message.what == what) {
738 mMessageEnvelopes.removeAt(i);
739 }
740 }
741 } // release lock
742}
743
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700744} // namespace android