blob: 4aa50d675f1699fec31d060a0c1f71562d1b37e2 [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
187 { // acquire lock
188 AutoMutex _l(mLock);
189 for (int i = 0; i < eventCount; i++) {
190 int fd = eventItems[i].data.fd;
191 uint32_t epollEvents = eventItems[i].events;
192 if (fd == mWakeReadPipeFd) {
193 if (epollEvents & EPOLLIN) {
194#if DEBUG_POLL_AND_WAKE
195 LOGD("%p ~ pollOnce - awoken", this);
196#endif
197 char buffer[16];
198 ssize_t nRead;
199 do {
200 nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
Jeff Brown171bf9e2010-09-16 17:04:52 -0700201 } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
Jeff Brown7901eb22010-09-13 23:17:30 -0700202 } else {
203 LOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
204 }
205 } else {
206 ssize_t requestIndex = mRequests.indexOfKey(fd);
207 if (requestIndex >= 0) {
208 int events = 0;
209 if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;
210 if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;
211 if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;
212 if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;
213
214 Response response;
215 response.events = events;
216 response.request = mRequests.valueAt(requestIndex);
217 mResponses.push(response);
218 } else {
219 LOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
220 "no longer registered.", epollEvents, fd);
221 }
222 }
223 }
224 }
225
226 for (size_t i = 0; i < mResponses.size(); i++) {
227 const Response& response = mResponses.itemAt(i);
228 if (response.request.callback) {
229#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
230 LOGD("%p ~ pollOnce - invoking callback: fd=%d, events=0x%x, data=%p", this,
231 response.request.fd, response.events, response.request.data);
232#endif
233 int callbackResult = response.request.callback(
234 response.request.fd, response.events, response.request.data);
235 if (callbackResult == 0) {
236 removeFd(response.request.fd);
237 }
238
239 result = ALOOPER_POLL_CALLBACK;
240 }
241 }
242 return result;
243}
244
245int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
246 if (timeoutMillis <= 0) {
247 int result;
248 do {
249 result = pollOnce(timeoutMillis, outFd, outEvents, outData);
250 } while (result == ALOOPER_POLL_CALLBACK);
251 return result;
252 } else {
253 nsecs_t endTime = systemTime(SYSTEM_TIME_MONOTONIC)
254 + milliseconds_to_nanoseconds(timeoutMillis);
255
256 for (;;) {
257 int result = pollOnce(timeoutMillis, outFd, outEvents, outData);
258 if (result != ALOOPER_POLL_CALLBACK) {
259 return result;
260 }
261
262 nsecs_t timeoutNanos = endTime - systemTime(SYSTEM_TIME_MONOTONIC);
263 if (timeoutNanos <= 0) {
264 return ALOOPER_POLL_TIMEOUT;
265 }
266
267 timeoutMillis = int(nanoseconds_to_milliseconds(timeoutNanos + 999999LL));
268 }
269 }
270}
271
272void Looper::wake() {
273#if DEBUG_POLL_AND_WAKE
274 LOGD("%p ~ wake", this);
275#endif
276
Jeff Brown171bf9e2010-09-16 17:04:52 -0700277 ssize_t nWrite;
278 do {
279 nWrite = write(mWakeWritePipeFd, "W", 1);
280 } while (nWrite == -1 && errno == EINTR);
281
Jeff Brown7901eb22010-09-13 23:17:30 -0700282 if (nWrite != 1) {
283 if (errno != EAGAIN) {
284 LOGW("Could not write wake signal, errno=%d", errno);
285 }
286 }
287}
288
289int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) {
290#if DEBUG_CALLBACKS
291 LOGD("%p ~ addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident,
292 events, callback, data);
293#endif
294
295 int epollEvents = 0;
296 if (events & ALOOPER_EVENT_INPUT) epollEvents |= EPOLLIN;
297 if (events & ALOOPER_EVENT_OUTPUT) epollEvents |= EPOLLOUT;
298 if (events & ALOOPER_EVENT_ERROR) epollEvents |= EPOLLERR;
299 if (events & ALOOPER_EVENT_HANGUP) epollEvents |= EPOLLHUP;
300
301 if (epollEvents == 0) {
302 LOGE("Invalid attempt to set a callback with no selected poll events.");
303 return -1;
304 }
305
306 if (! callback) {
307 if (! mAllowNonCallbacks) {
308 LOGE("Invalid attempt to set NULL callback but not allowed for this looper.");
309 return -1;
310 }
311
312 if (ident < 0) {
313 LOGE("Invalid attempt to set NULL callback with ident <= 0.");
314 return -1;
315 }
316 }
317
318 { // acquire lock
319 AutoMutex _l(mLock);
320
321 Request request;
322 request.fd = fd;
323 request.ident = ident;
324 request.callback = callback;
325 request.data = data;
326
327 struct epoll_event eventItem;
328 eventItem.events = epollEvents;
329 eventItem.data.fd = fd;
330
331 ssize_t requestIndex = mRequests.indexOfKey(fd);
332 if (requestIndex < 0) {
333 int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
334 if (epollResult < 0) {
335 LOGE("Error adding epoll events for fd %d, errno=%d", fd, errno);
336 return -1;
337 }
338 mRequests.add(fd, request);
339 } else {
340 int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
341 if (epollResult < 0) {
342 LOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno);
343 return -1;
344 }
345 mRequests.replaceValueAt(requestIndex, request);
346 }
347 } // release lock
348 return 1;
349}
350
351int Looper::removeFd(int fd) {
352#if DEBUG_CALLBACKS
353 LOGD("%p ~ removeFd - fd=%d", this, fd);
354#endif
355
356 { // acquire lock
357 AutoMutex _l(mLock);
358 ssize_t requestIndex = mRequests.indexOfKey(fd);
359 if (requestIndex < 0) {
360 return 0;
361 }
362
363 int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
364 if (epollResult < 0) {
365 LOGE("Error removing epoll events for fd %d, errno=%d", fd, errno);
366 return -1;
367 }
368
369 mRequests.removeItemsAt(requestIndex);
370 } // request lock
371 return 1;
372}
373
374} // namespace android