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