blob: d2dd6eb48e5df7774ce1e3113fd00c2491b0cf73 [file] [log] [blame]
Jeff Brown7901eb22010-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>
22#include <sys/epoll.h>
23
24
25namespace android {
26
Jeff Brown7901eb22010-09-13 23:17:30 -070027// Hint for number of file descriptors to be associated with the epoll instance.
28static const int EPOLL_SIZE_HINT = 8;
29
30// Maximum number of file descriptors for which to retrieve poll events each iteration.
31static const int EPOLL_MAX_EVENTS = 16;
32
Jeff Brownd1805182010-09-21 15:11:18 -070033static pthread_once_t gTLSOnce = PTHREAD_ONCE_INIT;
34static pthread_key_t gTLSKey = 0;
35
Jeff Brown7901eb22010-09-13 23:17:30 -070036Looper::Looper(bool allowNonCallbacks) :
37 mAllowNonCallbacks(allowNonCallbacks),
38 mResponseIndex(0) {
39 mEpollFd = epoll_create(EPOLL_SIZE_HINT);
40 LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
41
42 int wakeFds[2];
43 int result = pipe(wakeFds);
44 LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
45
46 mWakeReadPipeFd = wakeFds[0];
47 mWakeWritePipeFd = wakeFds[1];
48
49 result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
50 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
51 errno);
52
53 result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
54 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
55 errno);
56
57 struct epoll_event eventItem;
Jeff Brownd1805182010-09-21 15:11:18 -070058 memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
Jeff Brown7901eb22010-09-13 23:17:30 -070059 eventItem.events = EPOLLIN;
60 eventItem.data.fd = mWakeReadPipeFd;
61 result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
62 LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
63 errno);
64}
65
66Looper::~Looper() {
67 close(mWakeReadPipeFd);
68 close(mWakeWritePipeFd);
69 close(mEpollFd);
70}
71
Jeff Brownd1805182010-09-21 15:11:18 -070072void Looper::initTLSKey() {
73 int result = pthread_key_create(& gTLSKey, threadDestructor);
74 LOG_ALWAYS_FATAL_IF(result != 0, "Could not allocate TLS key.");
75}
76
Jeff Brown7901eb22010-09-13 23:17:30 -070077void Looper::threadDestructor(void *st) {
78 Looper* const self = static_cast<Looper*>(st);
79 if (self != NULL) {
80 self->decStrong((void*)threadDestructor);
81 }
82}
83
84void Looper::setForThread(const sp<Looper>& looper) {
85 sp<Looper> old = getForThread(); // also has side-effect of initializing TLS
86
87 if (looper != NULL) {
88 looper->incStrong((void*)threadDestructor);
89 }
90
Jeff Brownd1805182010-09-21 15:11:18 -070091 pthread_setspecific(gTLSKey, looper.get());
Jeff Brown7901eb22010-09-13 23:17:30 -070092
93 if (old != NULL) {
94 old->decStrong((void*)threadDestructor);
95 }
96}
97
98sp<Looper> Looper::getForThread() {
Jeff Brownd1805182010-09-21 15:11:18 -070099 int result = pthread_once(& gTLSOnce, initTLSKey);
100 LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed");
Jeff Brown7901eb22010-09-13 23:17:30 -0700101
Jeff Brownd1805182010-09-21 15:11:18 -0700102 return (Looper*)pthread_getspecific(gTLSKey);
Jeff Brown7901eb22010-09-13 23:17:30 -0700103}
104
105sp<Looper> Looper::prepare(int opts) {
106 bool allowNonCallbacks = opts & ALOOPER_PREPARE_ALLOW_NON_CALLBACKS;
107 sp<Looper> looper = Looper::getForThread();
108 if (looper == NULL) {
109 looper = new Looper(allowNonCallbacks);
110 Looper::setForThread(looper);
111 }
112 if (looper->getAllowNonCallbacks() != allowNonCallbacks) {
113 LOGW("Looper already prepared for this thread with a different value for the "
114 "ALOOPER_PREPARE_ALLOW_NON_CALLBACKS option.");
115 }
116 return looper;
117}
118
119bool Looper::getAllowNonCallbacks() const {
120 return mAllowNonCallbacks;
121}
122
123int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
124 int result = 0;
125 for (;;) {
126 while (mResponseIndex < mResponses.size()) {
127 const Response& response = mResponses.itemAt(mResponseIndex++);
128 if (! response.request.callback) {
129#if DEBUG_POLL_AND_WAKE
130 LOGD("%p ~ pollOnce - returning signalled identifier %d: "
131 "fd=%d, events=0x%x, data=%p", this,
132 response.request.ident, response.request.fd,
133 response.events, response.request.data);
134#endif
135 if (outFd != NULL) *outFd = response.request.fd;
136 if (outEvents != NULL) *outEvents = response.events;
137 if (outData != NULL) *outData = response.request.data;
138 return response.request.ident;
139 }
140 }
141
142 if (result != 0) {
143#if DEBUG_POLL_AND_WAKE
144 LOGD("%p ~ pollOnce - returning result %d", this, result);
145#endif
146 if (outFd != NULL) *outFd = 0;
147 if (outEvents != NULL) *outEvents = NULL;
148 if (outData != NULL) *outData = NULL;
149 return result;
150 }
151
152 result = pollInner(timeoutMillis);
153 }
154}
155
156int Looper::pollInner(int timeoutMillis) {
157#if DEBUG_POLL_AND_WAKE
158 LOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
159#endif
160 struct epoll_event eventItems[EPOLL_MAX_EVENTS];
161 int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
162 if (eventCount < 0) {
Jeff Brown171bf9e2010-09-16 17:04:52 -0700163 if (errno == EINTR) {
164 return ALOOPER_POLL_WAKE;
Jeff Brown7901eb22010-09-13 23:17:30 -0700165 }
Jeff Brown171bf9e2010-09-16 17:04:52 -0700166
167 LOGW("Poll failed with an unexpected error, errno=%d", errno);
Jeff Brown7901eb22010-09-13 23:17:30 -0700168 return ALOOPER_POLL_ERROR;
169 }
170
171 if (eventCount == 0) {
172#if DEBUG_POLL_AND_WAKE
173 LOGD("%p ~ pollOnce - timeout", this);
174#endif
175 return ALOOPER_POLL_TIMEOUT;
176 }
177
178 int result = ALOOPER_POLL_WAKE;
179 mResponses.clear();
180 mResponseIndex = 0;
181
182#if DEBUG_POLL_AND_WAKE
183 LOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
184#endif
Jeff Brown9da18102010-09-17 17:01:23 -0700185 bool acquiredLock = false;
186 for (int i = 0; i < eventCount; i++) {
187 int fd = eventItems[i].data.fd;
188 uint32_t epollEvents = eventItems[i].events;
189 if (fd == mWakeReadPipeFd) {
190 if (epollEvents & EPOLLIN) {
Jeff Brown7901eb22010-09-13 23:17:30 -0700191#if DEBUG_POLL_AND_WAKE
Jeff Brown9da18102010-09-17 17:01:23 -0700192 LOGD("%p ~ pollOnce - awoken", this);
Jeff Brown7901eb22010-09-13 23:17:30 -0700193#endif
Jeff Brown9da18102010-09-17 17:01:23 -0700194 char buffer[16];
195 ssize_t nRead;
196 do {
197 nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
198 } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
Jeff Brown7901eb22010-09-13 23:17:30 -0700199 } else {
Jeff Brown9da18102010-09-17 17:01:23 -0700200 LOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
201 }
202 } else {
203 if (! acquiredLock) {
204 mLock.lock();
205 acquiredLock = true;
206 }
Jeff Brown7901eb22010-09-13 23:17:30 -0700207
Jeff Brown9da18102010-09-17 17:01:23 -0700208 ssize_t requestIndex = mRequests.indexOfKey(fd);
209 if (requestIndex >= 0) {
210 int events = 0;
211 if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;
212 if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;
213 if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;
214 if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;
215
216 Response response;
217 response.events = events;
218 response.request = mRequests.valueAt(requestIndex);
219 mResponses.push(response);
220 } else {
221 LOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
222 "no longer registered.", epollEvents, fd);
Jeff Brown7901eb22010-09-13 23:17:30 -0700223 }
224 }
225 }
Jeff Brown9da18102010-09-17 17:01:23 -0700226 if (acquiredLock) {
227 mLock.unlock();
228 }
Jeff Brown7901eb22010-09-13 23:17:30 -0700229
230 for (size_t i = 0; i < mResponses.size(); i++) {
231 const Response& response = mResponses.itemAt(i);
232 if (response.request.callback) {
233#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
234 LOGD("%p ~ pollOnce - invoking callback: fd=%d, events=0x%x, data=%p", this,
235 response.request.fd, response.events, response.request.data);
236#endif
237 int callbackResult = response.request.callback(
238 response.request.fd, response.events, response.request.data);
239 if (callbackResult == 0) {
240 removeFd(response.request.fd);
241 }
242
243 result = ALOOPER_POLL_CALLBACK;
244 }
245 }
246 return result;
247}
248
249int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
250 if (timeoutMillis <= 0) {
251 int result;
252 do {
253 result = pollOnce(timeoutMillis, outFd, outEvents, outData);
254 } while (result == ALOOPER_POLL_CALLBACK);
255 return result;
256 } else {
257 nsecs_t endTime = systemTime(SYSTEM_TIME_MONOTONIC)
258 + milliseconds_to_nanoseconds(timeoutMillis);
259
260 for (;;) {
261 int result = pollOnce(timeoutMillis, outFd, outEvents, outData);
262 if (result != ALOOPER_POLL_CALLBACK) {
263 return result;
264 }
265
266 nsecs_t timeoutNanos = endTime - systemTime(SYSTEM_TIME_MONOTONIC);
267 if (timeoutNanos <= 0) {
268 return ALOOPER_POLL_TIMEOUT;
269 }
270
271 timeoutMillis = int(nanoseconds_to_milliseconds(timeoutNanos + 999999LL));
272 }
273 }
274}
275
276void Looper::wake() {
277#if DEBUG_POLL_AND_WAKE
278 LOGD("%p ~ wake", this);
279#endif
280
Jeff Brown171bf9e2010-09-16 17:04:52 -0700281 ssize_t nWrite;
282 do {
283 nWrite = write(mWakeWritePipeFd, "W", 1);
284 } while (nWrite == -1 && errno == EINTR);
285
Jeff Brown7901eb22010-09-13 23:17:30 -0700286 if (nWrite != 1) {
287 if (errno != EAGAIN) {
288 LOGW("Could not write wake signal, errno=%d", errno);
289 }
290 }
291}
292
293int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) {
294#if DEBUG_CALLBACKS
295 LOGD("%p ~ addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident,
296 events, callback, data);
297#endif
298
299 int epollEvents = 0;
300 if (events & ALOOPER_EVENT_INPUT) epollEvents |= EPOLLIN;
301 if (events & ALOOPER_EVENT_OUTPUT) epollEvents |= EPOLLOUT;
302 if (events & ALOOPER_EVENT_ERROR) epollEvents |= EPOLLERR;
303 if (events & ALOOPER_EVENT_HANGUP) epollEvents |= EPOLLHUP;
304
305 if (epollEvents == 0) {
306 LOGE("Invalid attempt to set a callback with no selected poll events.");
307 return -1;
308 }
309
310 if (! callback) {
311 if (! mAllowNonCallbacks) {
312 LOGE("Invalid attempt to set NULL callback but not allowed for this looper.");
313 return -1;
314 }
315
316 if (ident < 0) {
317 LOGE("Invalid attempt to set NULL callback with ident <= 0.");
318 return -1;
319 }
320 }
321
322 { // acquire lock
323 AutoMutex _l(mLock);
324
325 Request request;
326 request.fd = fd;
327 request.ident = ident;
328 request.callback = callback;
329 request.data = data;
330
331 struct epoll_event eventItem;
Jeff Brownd1805182010-09-21 15:11:18 -0700332 memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
Jeff Brown7901eb22010-09-13 23:17:30 -0700333 eventItem.events = epollEvents;
334 eventItem.data.fd = fd;
335
336 ssize_t requestIndex = mRequests.indexOfKey(fd);
337 if (requestIndex < 0) {
338 int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
339 if (epollResult < 0) {
340 LOGE("Error adding epoll events for fd %d, errno=%d", fd, errno);
341 return -1;
342 }
343 mRequests.add(fd, request);
344 } else {
345 int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
346 if (epollResult < 0) {
347 LOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno);
348 return -1;
349 }
350 mRequests.replaceValueAt(requestIndex, request);
351 }
352 } // release lock
353 return 1;
354}
355
356int Looper::removeFd(int fd) {
357#if DEBUG_CALLBACKS
358 LOGD("%p ~ removeFd - fd=%d", this, fd);
359#endif
360
361 { // acquire lock
362 AutoMutex _l(mLock);
363 ssize_t requestIndex = mRequests.indexOfKey(fd);
364 if (requestIndex < 0) {
365 return 0;
366 }
367
368 int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
369 if (epollResult < 0) {
370 LOGE("Error removing epoll events for fd %d, errno=%d", fd, errno);
371 return -1;
372 }
373
374 mRequests.removeItemsAt(requestIndex);
375 } // request lock
376 return 1;
377}
378
379} // namespace android