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