blob: 58fe1411d99aa080608eb3c71606888b99fb9f89 [file] [log] [blame]
Jeff Browne839a582010-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 Brownf4a4ec22010-06-16 01:53:36 -070014#define DEBUG_CALLBACKS 0
Jeff Browne839a582010-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 Hackbornefa10852010-07-02 18:52:01 -070024static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
25static bool gHaveTLS = false;
26static pthread_key_t gTLS = 0;
27
Jeff Browne839a582010-04-22 18:58:52 -070028PollLoop::PollLoop() :
Jeff Brownf4a4ec22010-06-16 01:53:36 -070029 mPolling(false), mWaiters(0) {
Jeff Browne839a582010-04-22 18:58:52 -070030 openWakePipe();
31}
32
33PollLoop::~PollLoop() {
34 closeWakePipe();
35}
36
Dianne Hackbornefa10852010-07-02 18:52:01 -070037void PollLoop::threadDestructor(void *st) {
38 PollLoop* const self = static_cast<PollLoop*>(st);
39 if (self != NULL) {
40 self->decStrong((void*)threadDestructor);
41 }
42}
43
44void PollLoop::setForThread(const sp<PollLoop>& pollLoop) {
45 sp<PollLoop> old = getForThread();
46
47 if (pollLoop != NULL) {
48 pollLoop->incStrong((void*)threadDestructor);
49 }
50
51 pthread_setspecific(gTLS, pollLoop.get());
52
53 if (old != NULL) {
54 old->decStrong((void*)threadDestructor);
55 }
56}
57
58sp<PollLoop> PollLoop::getForThread() {
59 if (!gHaveTLS) {
60 pthread_mutex_lock(&gTLSMutex);
61 if (pthread_key_create(&gTLS, threadDestructor) != 0) {
62 pthread_mutex_unlock(&gTLSMutex);
63 return NULL;
64 }
65 gHaveTLS = true;
66 pthread_mutex_unlock(&gTLSMutex);
67 }
68
69 return (PollLoop*)pthread_getspecific(gTLS);
70}
71
Jeff Browne839a582010-04-22 18:58:52 -070072void PollLoop::openWakePipe() {
73 int wakeFds[2];
74 int result = pipe(wakeFds);
75 LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
76
77 mWakeReadPipeFd = wakeFds[0];
78 mWakeWritePipeFd = wakeFds[1];
79
80 result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
81 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
82 errno);
83
84 result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
85 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
86 errno);
87
88 // Add the wake pipe to the head of the request list with a null callback.
89 struct pollfd requestedFd;
90 requestedFd.fd = mWakeReadPipeFd;
91 requestedFd.events = POLLIN;
92 mRequestedFds.insertAt(requestedFd, 0);
93
94 RequestedCallback requestedCallback;
95 requestedCallback.callback = NULL;
Dianne Hackbornefa10852010-07-02 18:52:01 -070096 requestedCallback.looperCallback = NULL;
Jeff Browne839a582010-04-22 18:58:52 -070097 requestedCallback.data = NULL;
98 mRequestedCallbacks.insertAt(requestedCallback, 0);
99}
100
101void PollLoop::closeWakePipe() {
102 close(mWakeReadPipeFd);
103 close(mWakeWritePipeFd);
104
105 // Note: We don't need to remove the poll structure or callback entry because this
106 // method is currently only called by the destructor.
107}
108
109bool PollLoop::pollOnce(int timeoutMillis) {
110 mLock.lock();
Jeff Brownf4a4ec22010-06-16 01:53:36 -0700111 while (mWaiters != 0) {
112 mResume.wait(mLock);
113 }
Jeff Browne839a582010-04-22 18:58:52 -0700114 mPolling = true;
115 mLock.unlock();
116
117 bool result;
118 size_t requestedCount = mRequestedFds.size();
119
120#if DEBUG_POLL_AND_WAKE
121 LOGD("%p ~ pollOnce - waiting on %d fds", this, requestedCount);
122 for (size_t i = 0; i < requestedCount; i++) {
123 LOGD(" fd %d - events %d", mRequestedFds[i].fd, mRequestedFds[i].events);
124 }
125#endif
126
127 int respondedCount = poll(mRequestedFds.editArray(), requestedCount, timeoutMillis);
128
129 if (respondedCount == 0) {
130 // Timeout
131#if DEBUG_POLL_AND_WAKE
132 LOGD("%p ~ pollOnce - timeout", this);
133#endif
134 result = false;
135 goto Done;
136 }
137
138 if (respondedCount < 0) {
139 // Error
140#if DEBUG_POLL_AND_WAKE
141 LOGD("%p ~ pollOnce - error, errno=%d", this, errno);
142#endif
143 if (errno != EINTR) {
144 LOGW("Poll failed with an unexpected error, errno=%d", errno);
145 }
146 result = false;
147 goto Done;
148 }
149
150#if DEBUG_POLL_AND_WAKE
151 LOGD("%p ~ pollOnce - handling responses from %d fds", this, respondedCount);
152 for (size_t i = 0; i < requestedCount; i++) {
153 LOGD(" fd %d - events %d, revents %d", mRequestedFds[i].fd, mRequestedFds[i].events,
154 mRequestedFds[i].revents);
155 }
156#endif
157
158 mPendingCallbacks.clear();
159 for (size_t i = 0; i < requestedCount; i++) {
160 const struct pollfd& requestedFd = mRequestedFds.itemAt(i);
161
162 short revents = requestedFd.revents;
163 if (revents) {
164 const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
165 Callback callback = requestedCallback.callback;
Dianne Hackbornefa10852010-07-02 18:52:01 -0700166 ALooper_callbackFunc* looperCallback = requestedCallback.looperCallback;
Jeff Browne839a582010-04-22 18:58:52 -0700167
Dianne Hackbornefa10852010-07-02 18:52:01 -0700168 if (callback || looperCallback) {
Jeff Browne839a582010-04-22 18:58:52 -0700169 PendingCallback pendingCallback;
170 pendingCallback.fd = requestedFd.fd;
171 pendingCallback.events = requestedFd.revents;
172 pendingCallback.callback = callback;
Dianne Hackbornefa10852010-07-02 18:52:01 -0700173 pendingCallback.looperCallback = looperCallback;
Jeff Browne839a582010-04-22 18:58:52 -0700174 pendingCallback.data = requestedCallback.data;
175 mPendingCallbacks.push(pendingCallback);
176 } else {
177 if (requestedFd.fd == mWakeReadPipeFd) {
178#if DEBUG_POLL_AND_WAKE
179 LOGD("%p ~ pollOnce - awoken", this);
180#endif
181 char buffer[16];
182 ssize_t nRead;
183 do {
184 nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
185 } while (nRead == sizeof(buffer));
186 } else {
187#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
188 LOGD("%p ~ pollOnce - fd %d has no callback!", this, requestedFd.fd);
189#endif
190 }
191 }
192
193 respondedCount -= 1;
194 if (respondedCount == 0) {
195 break;
196 }
197 }
198 }
199 result = true;
200
201Done:
202 mLock.lock();
203 mPolling = false;
Jeff Brownf4a4ec22010-06-16 01:53:36 -0700204 if (mWaiters != 0) {
205 mAwake.broadcast();
206 }
Jeff Browne839a582010-04-22 18:58:52 -0700207 mLock.unlock();
208
209 if (result) {
210 size_t pendingCount = mPendingCallbacks.size();
211 for (size_t i = 0; i < pendingCount; i++) {
212 const PendingCallback& pendingCallback = mPendingCallbacks.itemAt(i);
213#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
214 LOGD("%p ~ pollOnce - invoking callback for fd %d", this, pendingCallback.fd);
215#endif
216
Dianne Hackbornefa10852010-07-02 18:52:01 -0700217 bool keep = true;
218 if (pendingCallback.callback != NULL) {
219 keep = pendingCallback.callback(pendingCallback.fd, pendingCallback.events,
220 pendingCallback.data);
221 } else {
222 keep = pendingCallback.looperCallback(pendingCallback.fd, pendingCallback.events,
223 pendingCallback.data) != 0;
224 }
Jeff Browne839a582010-04-22 18:58:52 -0700225 if (! keep) {
226 removeCallback(pendingCallback.fd);
227 }
228 }
229 }
230
231#if DEBUG_POLL_AND_WAKE
232 LOGD("%p ~ pollOnce - done", this);
233#endif
234 return result;
235}
236
237void PollLoop::wake() {
238#if DEBUG_POLL_AND_WAKE
239 LOGD("%p ~ wake", this);
240#endif
241
242 ssize_t nWrite = write(mWakeWritePipeFd, "W", 1);
243 if (nWrite != 1) {
244 if (errno != EAGAIN) {
245 LOGW("Could not write wake signal, errno=%d", errno);
246 }
247 }
248}
249
250void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
Dianne Hackbornefa10852010-07-02 18:52:01 -0700251 setCallbackCommon(fd, events, callback, NULL, data);
252}
253
254void PollLoop::setLooperCallback(int fd, int events, ALooper_callbackFunc* callback,
255 void* data) {
256 setCallbackCommon(fd, events, NULL, callback, data);
257}
258
259void PollLoop::setCallbackCommon(int fd, int events, Callback callback,
260 ALooper_callbackFunc* looperCallback, void* data) {
261
Jeff Browne839a582010-04-22 18:58:52 -0700262#if DEBUG_CALLBACKS
263 LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events);
264#endif
265
Dianne Hackbornefa10852010-07-02 18:52:01 -0700266 if (! events || (! callback && ! looperCallback)) {
Jeff Browne839a582010-04-22 18:58:52 -0700267 LOGE("Invalid attempt to set a callback with no selected poll events or no callback.");
268 removeCallback(fd);
269 return;
270 }
271
272 wakeAndLock();
273
274 struct pollfd requestedFd;
275 requestedFd.fd = fd;
276 requestedFd.events = events;
277
278 RequestedCallback requestedCallback;
279 requestedCallback.callback = callback;
Dianne Hackbornefa10852010-07-02 18:52:01 -0700280 requestedCallback.looperCallback = looperCallback;
Jeff Browne839a582010-04-22 18:58:52 -0700281 requestedCallback.data = data;
282
283 ssize_t index = getRequestIndexLocked(fd);
284 if (index < 0) {
285 mRequestedFds.push(requestedFd);
286 mRequestedCallbacks.push(requestedCallback);
287 } else {
288 mRequestedFds.replaceAt(requestedFd, size_t(index));
289 mRequestedCallbacks.replaceAt(requestedCallback, size_t(index));
290 }
291
292 mLock.unlock();
293}
294
295bool PollLoop::removeCallback(int fd) {
296#if DEBUG_CALLBACKS
297 LOGD("%p ~ removeCallback - fd=%d", this, fd);
298#endif
299
300 wakeAndLock();
301
302 ssize_t index = getRequestIndexLocked(fd);
303 if (index >= 0) {
304 mRequestedFds.removeAt(size_t(index));
305 mRequestedCallbacks.removeAt(size_t(index));
306 }
307
308 mLock.unlock();
309 return index >= 0;
310}
311
312ssize_t PollLoop::getRequestIndexLocked(int fd) {
313 size_t requestCount = mRequestedFds.size();
314
315 for (size_t i = 0; i < requestCount; i++) {
316 if (mRequestedFds.itemAt(i).fd == fd) {
317 return i;
318 }
319 }
320
321 return -1;
322}
323
324void PollLoop::wakeAndLock() {
325 mLock.lock();
Jeff Brownf4a4ec22010-06-16 01:53:36 -0700326 mWaiters += 1;
Jeff Browne839a582010-04-22 18:58:52 -0700327 while (mPolling) {
328 wake();
329 mAwake.wait(mLock);
330 }
Jeff Brownf4a4ec22010-06-16 01:53:36 -0700331 mWaiters -= 1;
332 if (mWaiters == 0) {
333 mResume.signal();
334 }
Jeff Browne839a582010-04-22 18:58:52 -0700335}
336
337} // namespace android