blob: 90a3e8b35374c0c550da7c3e4e9cb36900b27e6a [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.
14#define DEBUG_CALLBACKS 1
15
16#include <cutils/log.h>
17#include <utils/PollLoop.h>
18
19#include <unistd.h>
20#include <fcntl.h>
21
22namespace android {
23
24PollLoop::PollLoop() :
25 mPolling(false) {
26 openWakePipe();
27}
28
29PollLoop::~PollLoop() {
30 closeWakePipe();
31}
32
33void PollLoop::openWakePipe() {
34 int wakeFds[2];
35 int result = pipe(wakeFds);
36 LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
37
38 mWakeReadPipeFd = wakeFds[0];
39 mWakeWritePipeFd = wakeFds[1];
40
41 result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
42 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
43 errno);
44
45 result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
46 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
47 errno);
48
49 // Add the wake pipe to the head of the request list with a null callback.
50 struct pollfd requestedFd;
51 requestedFd.fd = mWakeReadPipeFd;
52 requestedFd.events = POLLIN;
53 mRequestedFds.insertAt(requestedFd, 0);
54
55 RequestedCallback requestedCallback;
56 requestedCallback.callback = NULL;
57 requestedCallback.data = NULL;
58 mRequestedCallbacks.insertAt(requestedCallback, 0);
59}
60
61void PollLoop::closeWakePipe() {
62 close(mWakeReadPipeFd);
63 close(mWakeWritePipeFd);
64
65 // Note: We don't need to remove the poll structure or callback entry because this
66 // method is currently only called by the destructor.
67}
68
69bool PollLoop::pollOnce(int timeoutMillis) {
70 mLock.lock();
71 mPolling = true;
72 mLock.unlock();
73
74 bool result;
75 size_t requestedCount = mRequestedFds.size();
76
77#if DEBUG_POLL_AND_WAKE
78 LOGD("%p ~ pollOnce - waiting on %d fds", this, requestedCount);
79 for (size_t i = 0; i < requestedCount; i++) {
80 LOGD(" fd %d - events %d", mRequestedFds[i].fd, mRequestedFds[i].events);
81 }
82#endif
83
84 int respondedCount = poll(mRequestedFds.editArray(), requestedCount, timeoutMillis);
85
86 if (respondedCount == 0) {
87 // Timeout
88#if DEBUG_POLL_AND_WAKE
89 LOGD("%p ~ pollOnce - timeout", this);
90#endif
91 result = false;
92 goto Done;
93 }
94
95 if (respondedCount < 0) {
96 // Error
97#if DEBUG_POLL_AND_WAKE
98 LOGD("%p ~ pollOnce - error, errno=%d", this, errno);
99#endif
100 if (errno != EINTR) {
101 LOGW("Poll failed with an unexpected error, errno=%d", errno);
102 }
103 result = false;
104 goto Done;
105 }
106
107#if DEBUG_POLL_AND_WAKE
108 LOGD("%p ~ pollOnce - handling responses from %d fds", this, respondedCount);
109 for (size_t i = 0; i < requestedCount; i++) {
110 LOGD(" fd %d - events %d, revents %d", mRequestedFds[i].fd, mRequestedFds[i].events,
111 mRequestedFds[i].revents);
112 }
113#endif
114
115 mPendingCallbacks.clear();
116 for (size_t i = 0; i < requestedCount; i++) {
117 const struct pollfd& requestedFd = mRequestedFds.itemAt(i);
118
119 short revents = requestedFd.revents;
120 if (revents) {
121 const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
122 Callback callback = requestedCallback.callback;
123
124 if (callback) {
125 PendingCallback pendingCallback;
126 pendingCallback.fd = requestedFd.fd;
127 pendingCallback.events = requestedFd.revents;
128 pendingCallback.callback = callback;
129 pendingCallback.data = requestedCallback.data;
130 mPendingCallbacks.push(pendingCallback);
131 } else {
132 if (requestedFd.fd == mWakeReadPipeFd) {
133#if DEBUG_POLL_AND_WAKE
134 LOGD("%p ~ pollOnce - awoken", this);
135#endif
136 char buffer[16];
137 ssize_t nRead;
138 do {
139 nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
140 } while (nRead == sizeof(buffer));
141 } else {
142#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
143 LOGD("%p ~ pollOnce - fd %d has no callback!", this, requestedFd.fd);
144#endif
145 }
146 }
147
148 respondedCount -= 1;
149 if (respondedCount == 0) {
150 break;
151 }
152 }
153 }
154 result = true;
155
156Done:
157 mLock.lock();
158 mPolling = false;
159 mAwake.broadcast();
160 mLock.unlock();
161
162 if (result) {
163 size_t pendingCount = mPendingCallbacks.size();
164 for (size_t i = 0; i < pendingCount; i++) {
165 const PendingCallback& pendingCallback = mPendingCallbacks.itemAt(i);
166#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
167 LOGD("%p ~ pollOnce - invoking callback for fd %d", this, pendingCallback.fd);
168#endif
169
170 bool keep = pendingCallback.callback(pendingCallback.fd, pendingCallback.events,
171 pendingCallback.data);
172 if (! keep) {
173 removeCallback(pendingCallback.fd);
174 }
175 }
176 }
177
178#if DEBUG_POLL_AND_WAKE
179 LOGD("%p ~ pollOnce - done", this);
180#endif
181 return result;
182}
183
184void PollLoop::wake() {
185#if DEBUG_POLL_AND_WAKE
186 LOGD("%p ~ wake", this);
187#endif
188
189 ssize_t nWrite = write(mWakeWritePipeFd, "W", 1);
190 if (nWrite != 1) {
191 if (errno != EAGAIN) {
192 LOGW("Could not write wake signal, errno=%d", errno);
193 }
194 }
195}
196
197void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
198#if DEBUG_CALLBACKS
199 LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events);
200#endif
201
202 if (! events || ! callback) {
203 LOGE("Invalid attempt to set a callback with no selected poll events or no callback.");
204 removeCallback(fd);
205 return;
206 }
207
208 wakeAndLock();
209
210 struct pollfd requestedFd;
211 requestedFd.fd = fd;
212 requestedFd.events = events;
213
214 RequestedCallback requestedCallback;
215 requestedCallback.callback = callback;
216 requestedCallback.data = data;
217
218 ssize_t index = getRequestIndexLocked(fd);
219 if (index < 0) {
220 mRequestedFds.push(requestedFd);
221 mRequestedCallbacks.push(requestedCallback);
222 } else {
223 mRequestedFds.replaceAt(requestedFd, size_t(index));
224 mRequestedCallbacks.replaceAt(requestedCallback, size_t(index));
225 }
226
227 mLock.unlock();
228}
229
230bool PollLoop::removeCallback(int fd) {
231#if DEBUG_CALLBACKS
232 LOGD("%p ~ removeCallback - fd=%d", this, fd);
233#endif
234
235 wakeAndLock();
236
237 ssize_t index = getRequestIndexLocked(fd);
238 if (index >= 0) {
239 mRequestedFds.removeAt(size_t(index));
240 mRequestedCallbacks.removeAt(size_t(index));
241 }
242
243 mLock.unlock();
244 return index >= 0;
245}
246
247ssize_t PollLoop::getRequestIndexLocked(int fd) {
248 size_t requestCount = mRequestedFds.size();
249
250 for (size_t i = 0; i < requestCount; i++) {
251 if (mRequestedFds.itemAt(i).fd == fd) {
252 return i;
253 }
254 }
255
256 return -1;
257}
258
259void PollLoop::wakeAndLock() {
260 mLock.lock();
261 while (mPolling) {
262 wake();
263 mAwake.wait(mLock);
264 }
265}
266
267} // namespace android