blob: f740fa0d52557b354a901d95e0ed032b768a76b5 [file] [log] [blame]
Jeff Brown46b9ac0a2010-04-22 18:58:52 -07001//
2// Copyright 2010 The Android Open Source Project
3//
4// A select loop implementation.
5//
6#define LOG_TAG "PollLoop"
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.
Jeff Brown5c225b12010-06-16 01:53:36 -070014#define DEBUG_CALLBACKS 0
Jeff Brown46b9ac0a2010-04-22 18:58:52 -070015
16#include <cutils/log.h>
17#include <utils/PollLoop.h>
18
19#include <unistd.h>
20#include <fcntl.h>
21
22namespace android {
23
Dianne Hackborn68267412010-07-02 18:52:01 -070024static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
25static bool gHaveTLS = false;
26static pthread_key_t gTLS = 0;
27
Dianne Hackborn85448bb2010-07-07 14:27:31 -070028PollLoop::PollLoop(bool allowNonCallbacks) :
29 mAllowNonCallbacks(allowNonCallbacks), mPolling(false),
30 mWaiters(0), mPendingFdsPos(0) {
Jeff Brown46b9ac0a2010-04-22 18:58:52 -070031 openWakePipe();
32}
33
34PollLoop::~PollLoop() {
35 closeWakePipe();
36}
37
Dianne Hackborn68267412010-07-02 18:52:01 -070038void PollLoop::threadDestructor(void *st) {
39 PollLoop* const self = static_cast<PollLoop*>(st);
40 if (self != NULL) {
41 self->decStrong((void*)threadDestructor);
42 }
43}
44
45void PollLoop::setForThread(const sp<PollLoop>& pollLoop) {
46 sp<PollLoop> old = getForThread();
47
48 if (pollLoop != NULL) {
49 pollLoop->incStrong((void*)threadDestructor);
50 }
51
52 pthread_setspecific(gTLS, pollLoop.get());
53
54 if (old != NULL) {
55 old->decStrong((void*)threadDestructor);
56 }
57}
58
59sp<PollLoop> PollLoop::getForThread() {
60 if (!gHaveTLS) {
61 pthread_mutex_lock(&gTLSMutex);
62 if (pthread_key_create(&gTLS, threadDestructor) != 0) {
63 pthread_mutex_unlock(&gTLSMutex);
64 return NULL;
65 }
66 gHaveTLS = true;
67 pthread_mutex_unlock(&gTLSMutex);
68 }
69
70 return (PollLoop*)pthread_getspecific(gTLS);
71}
72
Jeff Brown46b9ac0a2010-04-22 18:58:52 -070073void PollLoop::openWakePipe() {
74 int wakeFds[2];
75 int result = pipe(wakeFds);
76 LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
77
78 mWakeReadPipeFd = wakeFds[0];
79 mWakeWritePipeFd = wakeFds[1];
80
81 result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
82 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
83 errno);
84
85 result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
86 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
87 errno);
88
89 // Add the wake pipe to the head of the request list with a null callback.
90 struct pollfd requestedFd;
91 requestedFd.fd = mWakeReadPipeFd;
92 requestedFd.events = POLLIN;
93 mRequestedFds.insertAt(requestedFd, 0);
94
95 RequestedCallback requestedCallback;
96 requestedCallback.callback = NULL;
Dianne Hackborn68267412010-07-02 18:52:01 -070097 requestedCallback.looperCallback = NULL;
Jeff Brown46b9ac0a2010-04-22 18:58:52 -070098 requestedCallback.data = NULL;
99 mRequestedCallbacks.insertAt(requestedCallback, 0);
100}
101
102void PollLoop::closeWakePipe() {
103 close(mWakeReadPipeFd);
104 close(mWakeWritePipeFd);
105
106 // Note: We don't need to remove the poll structure or callback entry because this
107 // method is currently only called by the destructor.
108}
109
Dianne Hackborn85448bb2010-07-07 14:27:31 -0700110int32_t PollLoop::pollOnce(int timeoutMillis, int* outEvents, void** outData) {
111 // If there are still pending fds from the last call, dispatch those
112 // first, to avoid an earlier fd from starving later ones.
113 const size_t pendingFdsCount = mPendingFds.size();
114 if (mPendingFdsPos < pendingFdsCount) {
115 const PendingCallback& pending = mPendingFds.itemAt(mPendingFdsPos);
116 mPendingFdsPos++;
117 if (outEvents != NULL) *outEvents = pending.events;
118 if (outData != NULL) *outData = pending.data;
119 return pending.fd;
120 }
121
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700122 mLock.lock();
Jeff Brown5c225b12010-06-16 01:53:36 -0700123 while (mWaiters != 0) {
124 mResume.wait(mLock);
125 }
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700126 mPolling = true;
127 mLock.unlock();
128
Dianne Hackborn85448bb2010-07-07 14:27:31 -0700129 int32_t result;
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700130 size_t requestedCount = mRequestedFds.size();
131
132#if DEBUG_POLL_AND_WAKE
133 LOGD("%p ~ pollOnce - waiting on %d fds", this, requestedCount);
134 for (size_t i = 0; i < requestedCount; i++) {
135 LOGD(" fd %d - events %d", mRequestedFds[i].fd, mRequestedFds[i].events);
136 }
137#endif
138
139 int respondedCount = poll(mRequestedFds.editArray(), requestedCount, timeoutMillis);
140
141 if (respondedCount == 0) {
142 // Timeout
143#if DEBUG_POLL_AND_WAKE
144 LOGD("%p ~ pollOnce - timeout", this);
145#endif
Dianne Hackborn85448bb2010-07-07 14:27:31 -0700146 result = POLL_TIMEOUT;
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700147 goto Done;
148 }
149
150 if (respondedCount < 0) {
151 // Error
152#if DEBUG_POLL_AND_WAKE
153 LOGD("%p ~ pollOnce - error, errno=%d", this, errno);
154#endif
155 if (errno != EINTR) {
156 LOGW("Poll failed with an unexpected error, errno=%d", errno);
157 }
Dianne Hackborn85448bb2010-07-07 14:27:31 -0700158 result = POLL_ERROR;
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700159 goto Done;
160 }
161
162#if DEBUG_POLL_AND_WAKE
163 LOGD("%p ~ pollOnce - handling responses from %d fds", this, respondedCount);
164 for (size_t i = 0; i < requestedCount; i++) {
165 LOGD(" fd %d - events %d, revents %d", mRequestedFds[i].fd, mRequestedFds[i].events,
166 mRequestedFds[i].revents);
167 }
168#endif
169
170 mPendingCallbacks.clear();
Dianne Hackborn85448bb2010-07-07 14:27:31 -0700171 mPendingFds.clear();
172 mPendingFdsPos = 0;
173 if (outEvents != NULL) *outEvents = 0;
174 if (outData != NULL) *outData = NULL;
175
176 result = POLL_CALLBACK;
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700177 for (size_t i = 0; i < requestedCount; i++) {
178 const struct pollfd& requestedFd = mRequestedFds.itemAt(i);
179
180 short revents = requestedFd.revents;
181 if (revents) {
182 const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
Dianne Hackborn85448bb2010-07-07 14:27:31 -0700183 PendingCallback pending;
184 pending.fd = requestedFd.fd;
185 pending.events = revents;
186 pending.callback = requestedCallback.callback;
187 pending.looperCallback = requestedCallback.looperCallback;
188 pending.data = requestedCallback.data;
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700189
Dianne Hackborn85448bb2010-07-07 14:27:31 -0700190 if (pending.callback || pending.looperCallback) {
191 mPendingCallbacks.push(pending);
192 } else if (pending.fd != mWakeReadPipeFd) {
193 if (result == POLL_CALLBACK) {
194 result = pending.fd;
195 if (outEvents != NULL) *outEvents = pending.events;
196 if (outData != NULL) *outData = pending.data;
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700197 } else {
Dianne Hackborn85448bb2010-07-07 14:27:31 -0700198 mPendingFds.push(pending);
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700199 }
Dianne Hackborn85448bb2010-07-07 14:27:31 -0700200 } else {
201#if DEBUG_POLL_AND_WAKE
202 LOGD("%p ~ pollOnce - awoken", this);
203#endif
204 char buffer[16];
205 ssize_t nRead;
206 do {
207 nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
208 } while (nRead == sizeof(buffer));
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700209 }
210
211 respondedCount -= 1;
212 if (respondedCount == 0) {
213 break;
214 }
215 }
216 }
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700217
218Done:
219 mLock.lock();
220 mPolling = false;
Jeff Brown5c225b12010-06-16 01:53:36 -0700221 if (mWaiters != 0) {
222 mAwake.broadcast();
223 }
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700224 mLock.unlock();
225
Dianne Hackborn85448bb2010-07-07 14:27:31 -0700226 if (result == POLL_CALLBACK || result >= 0) {
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700227 size_t pendingCount = mPendingCallbacks.size();
228 for (size_t i = 0; i < pendingCount; i++) {
229 const PendingCallback& pendingCallback = mPendingCallbacks.itemAt(i);
230#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
231 LOGD("%p ~ pollOnce - invoking callback for fd %d", this, pendingCallback.fd);
232#endif
233
Dianne Hackborn68267412010-07-02 18:52:01 -0700234 bool keep = true;
235 if (pendingCallback.callback != NULL) {
236 keep = pendingCallback.callback(pendingCallback.fd, pendingCallback.events,
237 pendingCallback.data);
238 } else {
239 keep = pendingCallback.looperCallback(pendingCallback.fd, pendingCallback.events,
240 pendingCallback.data) != 0;
241 }
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700242 if (! keep) {
243 removeCallback(pendingCallback.fd);
244 }
245 }
246 }
247
248#if DEBUG_POLL_AND_WAKE
249 LOGD("%p ~ pollOnce - done", this);
250#endif
251 return result;
252}
253
254void PollLoop::wake() {
255#if DEBUG_POLL_AND_WAKE
256 LOGD("%p ~ wake", this);
257#endif
258
259 ssize_t nWrite = write(mWakeWritePipeFd, "W", 1);
260 if (nWrite != 1) {
261 if (errno != EAGAIN) {
262 LOGW("Could not write wake signal, errno=%d", errno);
263 }
264 }
265}
266
Dianne Hackborn85448bb2010-07-07 14:27:31 -0700267bool PollLoop::getAllowNonCallbacks() const {
268 return mAllowNonCallbacks;
269}
270
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700271void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
Dianne Hackborn68267412010-07-02 18:52:01 -0700272 setCallbackCommon(fd, events, callback, NULL, data);
273}
274
275void PollLoop::setLooperCallback(int fd, int events, ALooper_callbackFunc* callback,
276 void* data) {
277 setCallbackCommon(fd, events, NULL, callback, data);
278}
279
280void PollLoop::setCallbackCommon(int fd, int events, Callback callback,
281 ALooper_callbackFunc* looperCallback, void* data) {
282
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700283#if DEBUG_CALLBACKS
284 LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events);
285#endif
286
Dianne Hackborn85448bb2010-07-07 14:27:31 -0700287 if (! events) {
288 LOGE("Invalid attempt to set a callback with no selected poll events.");
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700289 removeCallback(fd);
290 return;
291 }
292
Dianne Hackborn85448bb2010-07-07 14:27:31 -0700293 if (! callback && ! looperCallback && ! mAllowNonCallbacks) {
294 LOGE("Invalid attempt to set NULL callback but not allowed.");
295 removeCallback(fd);
296 return;
297 }
298
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700299 wakeAndLock();
300
301 struct pollfd requestedFd;
302 requestedFd.fd = fd;
303 requestedFd.events = events;
304
305 RequestedCallback requestedCallback;
306 requestedCallback.callback = callback;
Dianne Hackborn68267412010-07-02 18:52:01 -0700307 requestedCallback.looperCallback = looperCallback;
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700308 requestedCallback.data = data;
309
310 ssize_t index = getRequestIndexLocked(fd);
311 if (index < 0) {
312 mRequestedFds.push(requestedFd);
313 mRequestedCallbacks.push(requestedCallback);
314 } else {
315 mRequestedFds.replaceAt(requestedFd, size_t(index));
316 mRequestedCallbacks.replaceAt(requestedCallback, size_t(index));
317 }
318
319 mLock.unlock();
320}
321
322bool PollLoop::removeCallback(int fd) {
323#if DEBUG_CALLBACKS
324 LOGD("%p ~ removeCallback - fd=%d", this, fd);
325#endif
326
327 wakeAndLock();
328
329 ssize_t index = getRequestIndexLocked(fd);
330 if (index >= 0) {
331 mRequestedFds.removeAt(size_t(index));
332 mRequestedCallbacks.removeAt(size_t(index));
333 }
334
335 mLock.unlock();
336 return index >= 0;
337}
338
339ssize_t PollLoop::getRequestIndexLocked(int fd) {
340 size_t requestCount = mRequestedFds.size();
341
342 for (size_t i = 0; i < requestCount; i++) {
343 if (mRequestedFds.itemAt(i).fd == fd) {
344 return i;
345 }
346 }
347
348 return -1;
349}
350
351void PollLoop::wakeAndLock() {
352 mLock.lock();
Jeff Brown5c225b12010-06-16 01:53:36 -0700353 mWaiters += 1;
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700354 while (mPolling) {
355 wake();
356 mAwake.wait(mLock);
357 }
Jeff Brown5c225b12010-06-16 01:53:36 -0700358 mWaiters -= 1;
359 if (mWaiters == 0) {
360 mResume.signal();
361 }
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700362}
363
364} // namespace android