Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(166)

Side by Side Diff: runtime/bin/eventhandler_android.cc

Issue 172133004: Also make eventhandler on Android edge-triggered. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/bin/eventhandler_android.h ('k') | runtime/bin/eventhandler_linux.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "platform/globals.h" 5 #include "platform/globals.h"
6 #if defined(TARGET_OS_ANDROID) 6 #if defined(TARGET_OS_ANDROID)
7 7
8 #include "bin/eventhandler.h" 8 #include "bin/eventhandler.h"
9 9
10 #include <errno.h> // NOLINT 10 #include <errno.h> // NOLINT
(...skipping 16 matching lines...) Expand all
27 27
28 namespace dart { 28 namespace dart {
29 namespace bin { 29 namespace bin {
30 30
31 static const int kInterruptMessageSize = sizeof(InterruptMessage); 31 static const int kInterruptMessageSize = sizeof(InterruptMessage);
32 static const int kInfinityTimeout = -1; 32 static const int kInfinityTimeout = -1;
33 static const int kTimerId = -1; 33 static const int kTimerId = -1;
34 static const int kShutdownId = -2; 34 static const int kShutdownId = -2;
35 35
36 36
37 intptr_t SocketData::GetPollEvents() {
38 // Do not ask for EPOLLERR and EPOLLHUP explicitly as they are
39 // triggered anyway.
40 intptr_t events = 0;
41 if (!IsClosedRead()) {
42 if ((mask_ & (1 << kInEvent)) != 0) {
43 events |= EPOLLIN;
44 }
45 }
46 if (!IsClosedWrite()) {
47 if ((mask_ & (1 << kOutEvent)) != 0) {
48 events |= EPOLLOUT;
49 }
50 }
51 return events;
52 }
53
54
55 // Unregister the file descriptor for a SocketData structure with epoll. 37 // Unregister the file descriptor for a SocketData structure with epoll.
56 static void RemoveFromEpollInstance(intptr_t epoll_fd_, SocketData* sd) { 38 static void RemoveFromEpollInstance(intptr_t epoll_fd_, SocketData* sd) {
57 if (sd->tracked_by_epoll()) { 39 if (!sd->tracked_by_epoll()) return;
58 int status = TEMP_FAILURE_RETRY(epoll_ctl(epoll_fd_, 40 int status = TEMP_FAILURE_RETRY(epoll_ctl(epoll_fd_,
59 EPOLL_CTL_DEL, 41 EPOLL_CTL_DEL,
60 sd->fd(), 42 sd->fd(),
61 NULL)); 43 NULL));
62 if (status == -1) { 44 if (status == -1) {
63 FATAL("Failed unregistering events for file descriptor"); 45 FATAL("Failed unregistering events for file descriptor");
64 } 46 }
65 sd->set_tracked_by_epoll(false); 47 sd->set_tracked_by_epoll(false);
48 }
49
50
51 static void AddToEpollInstance(intptr_t epoll_fd_, SocketData* sd) {
52 ASSERT(!sd->tracked_by_epoll());
53 struct epoll_event event;
54 event.events = EPOLLET | EPOLLRDHUP;
55 if ((sd->mask() & (1 << kInEvent)) != 0) event.events |= EPOLLIN;
56 if ((sd->mask() & (1 << kOutEvent)) != 0) event.events |= EPOLLOUT;
57 event.data.ptr = sd;
58 int status = TEMP_FAILURE_RETRY(epoll_ctl(epoll_fd_,
59 EPOLL_CTL_ADD,
60 sd->fd(),
61 &event));
62 if (status == -1) {
63 // Epoll does not accept the file descriptor. It could be due to
64 // already closed file descriptor, or unuspported devices, such
65 // as /dev/null. In such case, mark the file descriptor as closed,
66 // so dart will handle it accordingly.
67 DartUtils::PostInt32(sd->port(), 1 << kCloseEvent);
68 } else {
69 sd->set_tracked_by_epoll(true);
66 } 70 }
67 } 71 }
68 72
69
70 // Register the file descriptor for a SocketData structure with epoll
71 // if events are requested.
72 static void UpdateEpollInstance(intptr_t epoll_fd_, SocketData* sd) {
73 struct epoll_event event;
74 event.events = sd->GetPollEvents();
75 event.data.ptr = sd;
76 if (sd->port() != 0 && event.events != 0) {
77 int status = 0;
78 if (sd->tracked_by_epoll()) {
79 status = TEMP_FAILURE_RETRY(epoll_ctl(epoll_fd_,
80 EPOLL_CTL_MOD,
81 sd->fd(),
82 &event));
83 } else {
84 status = TEMP_FAILURE_RETRY(epoll_ctl(epoll_fd_,
85 EPOLL_CTL_ADD,
86 sd->fd(),
87 &event));
88 sd->set_tracked_by_epoll(true);
89 }
90 if (status == -1) {
91 const int kBufferSize = 1024;
92 char error_message[kBufferSize];
93 strerror_r(errno, error_message, kBufferSize);
94 FATAL1("Failed updating epoll instance: %s", error_message);
95 }
96 }
97 }
98
99 73
100 EventHandlerImplementation::EventHandlerImplementation() 74 EventHandlerImplementation::EventHandlerImplementation()
101 : socket_map_(&HashMap::SamePointerValue, 16) { 75 : socket_map_(&HashMap::SamePointerValue, 16) {
102 intptr_t result; 76 intptr_t result;
103 result = TEMP_FAILURE_RETRY(pipe(interrupt_fds_)); 77 result = TEMP_FAILURE_RETRY(pipe(interrupt_fds_));
104 if (result != 0) { 78 if (result != 0) {
105 FATAL("Pipe creation failed"); 79 FATAL("Pipe creation failed");
106 } 80 }
107 FDUtils::SetNonBlocking(interrupt_fds_[0]); 81 FDUtils::SetNonBlocking(interrupt_fds_[0]);
108 FDUtils::SetCloseOnExec(interrupt_fds_[0]); 82 FDUtils::SetCloseOnExec(interrupt_fds_[0]);
(...skipping 20 matching lines...) Expand all
129 } 103 }
130 } 104 }
131 105
132 106
133 EventHandlerImplementation::~EventHandlerImplementation() { 107 EventHandlerImplementation::~EventHandlerImplementation() {
134 TEMP_FAILURE_RETRY(close(interrupt_fds_[0])); 108 TEMP_FAILURE_RETRY(close(interrupt_fds_[0]));
135 TEMP_FAILURE_RETRY(close(interrupt_fds_[1])); 109 TEMP_FAILURE_RETRY(close(interrupt_fds_[1]));
136 } 110 }
137 111
138 112
139 SocketData* EventHandlerImplementation::GetSocketData(intptr_t fd) { 113 SocketData* EventHandlerImplementation::GetSocketData(intptr_t fd,
114 bool* is_new) {
140 ASSERT(fd >= 0); 115 ASSERT(fd >= 0);
141 HashMap::Entry* entry = socket_map_.Lookup( 116 HashMap::Entry* entry = socket_map_.Lookup(
142 GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd), true); 117 GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd), true);
143 ASSERT(entry != NULL); 118 ASSERT(entry != NULL);
144 SocketData* sd = reinterpret_cast<SocketData*>(entry->value); 119 SocketData* sd = reinterpret_cast<SocketData*>(entry->value);
145 if (sd == NULL) { 120 if (sd == NULL) {
146 // If there is no data in the hash map for this file descriptor a 121 // If there is no data in the hash map for this file descriptor a
147 // new SocketData for the file descriptor is inserted. 122 // new SocketData for the file descriptor is inserted.
148 sd = new SocketData(fd); 123 sd = new SocketData(fd);
149 entry->value = sd; 124 entry->value = sd;
125 *is_new = true;
150 } 126 }
151 ASSERT(fd == sd->fd()); 127 ASSERT(fd == sd->fd());
152 return sd; 128 return sd;
153 } 129 }
154 130
155 131
156 void EventHandlerImplementation::WakeupHandler(intptr_t id, 132 void EventHandlerImplementation::WakeupHandler(intptr_t id,
157 Dart_Port dart_port, 133 Dart_Port dart_port,
158 int64_t data) { 134 int64_t data) {
159 InterruptMessage msg; 135 InterruptMessage msg;
(...skipping 19 matching lines...) Expand all
179 const intptr_t MAX_MESSAGES = kInterruptMessageSize; 155 const intptr_t MAX_MESSAGES = kInterruptMessageSize;
180 InterruptMessage msg[MAX_MESSAGES]; 156 InterruptMessage msg[MAX_MESSAGES];
181 ssize_t bytes = TEMP_FAILURE_RETRY( 157 ssize_t bytes = TEMP_FAILURE_RETRY(
182 read(interrupt_fds_[0], msg, MAX_MESSAGES * kInterruptMessageSize)); 158 read(interrupt_fds_[0], msg, MAX_MESSAGES * kInterruptMessageSize));
183 for (ssize_t i = 0; i < bytes / kInterruptMessageSize; i++) { 159 for (ssize_t i = 0; i < bytes / kInterruptMessageSize; i++) {
184 if (msg[i].id == kTimerId) { 160 if (msg[i].id == kTimerId) {
185 timeout_queue_.UpdateTimeout(msg[i].dart_port, msg[i].data); 161 timeout_queue_.UpdateTimeout(msg[i].dart_port, msg[i].data);
186 } else if (msg[i].id == kShutdownId) { 162 } else if (msg[i].id == kShutdownId) {
187 shutdown_ = true; 163 shutdown_ = true;
188 } else { 164 } else {
189 SocketData* sd = GetSocketData(msg[i].id); 165 bool is_new = false;
166 SocketData* sd = GetSocketData(msg[i].id, &is_new);
167 if (is_new) {
168 sd->SetPortAndMask(msg[i].dart_port, msg[i].data);
169 AddToEpollInstance(epoll_fd_, sd);
170 }
190 if ((msg[i].data & (1 << kShutdownReadCommand)) != 0) { 171 if ((msg[i].data & (1 << kShutdownReadCommand)) != 0) {
191 ASSERT(msg[i].data == (1 << kShutdownReadCommand)); 172 ASSERT(msg[i].data == (1 << kShutdownReadCommand));
192 // Close the socket for reading. 173 // Close the socket for reading.
193 sd->ShutdownRead(); 174 sd->ShutdownRead();
194 UpdateEpollInstance(epoll_fd_, sd);
195 } else if ((msg[i].data & (1 << kShutdownWriteCommand)) != 0) { 175 } else if ((msg[i].data & (1 << kShutdownWriteCommand)) != 0) {
196 ASSERT(msg[i].data == (1 << kShutdownWriteCommand)); 176 ASSERT(msg[i].data == (1 << kShutdownWriteCommand));
197 // Close the socket for writing. 177 // Close the socket for writing.
198 sd->ShutdownWrite(); 178 sd->ShutdownWrite();
199 UpdateEpollInstance(epoll_fd_, sd);
200 } else if ((msg[i].data & (1 << kCloseCommand)) != 0) { 179 } else if ((msg[i].data & (1 << kCloseCommand)) != 0) {
201 ASSERT(msg[i].data == (1 << kCloseCommand)); 180 ASSERT(msg[i].data == (1 << kCloseCommand));
202 // Close the socket and free system resources and move on to 181 // Close the socket and free system resources and move on to
203 // next message. 182 // next message.
204 RemoveFromEpollInstance(epoll_fd_, sd); 183 RemoveFromEpollInstance(epoll_fd_, sd);
205 intptr_t fd = sd->fd(); 184 intptr_t fd = sd->fd();
206 sd->Close(); 185 sd->Close();
207 socket_map_.Remove(GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd)); 186 socket_map_.Remove(GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd));
208 delete sd; 187 delete sd;
209 DartUtils::PostInt32(msg[i].dart_port, 1 << kDestroyedEvent); 188 DartUtils::PostInt32(msg[i].dart_port, 1 << kDestroyedEvent);
210 } else {
211 // Setup events to wait for.
212 sd->SetPortAndMask(msg[i].dart_port, msg[i].data);
213 UpdateEpollInstance(epoll_fd_, sd);
214 } 189 }
215 } 190 }
216 } 191 }
217 } 192 }
218 193
219 #ifdef DEBUG_POLL 194 #ifdef DEBUG_POLL
220 static void PrintEventMask(intptr_t fd, intptr_t events) { 195 static void PrintEventMask(intptr_t fd, intptr_t events) {
221 Log::Print("%d ", fd); 196 Log::Print("%d ", fd);
222 if ((events & EPOLLIN) != 0) Log::Print("EPOLLIN "); 197 if ((events & EPOLLIN) != 0) Log::Print("EPOLLIN ");
223 if ((events & EPOLLPRI) != 0) Log::Print("EPOLLPRI "); 198 if ((events & EPOLLPRI) != 0) Log::Print("EPOLLPRI ");
(...skipping 22 matching lines...) Expand all
246 // For listening sockets the EPOLLIN event indicate that there are 221 // For listening sockets the EPOLLIN event indicate that there are
247 // connections ready for accept unless accompanied with one of the 222 // connections ready for accept unless accompanied with one of the
248 // other flags. 223 // other flags.
249 if ((events & EPOLLIN) != 0) { 224 if ((events & EPOLLIN) != 0) {
250 if ((events & EPOLLHUP) != 0) event_mask |= (1 << kCloseEvent); 225 if ((events & EPOLLHUP) != 0) event_mask |= (1 << kCloseEvent);
251 if ((events & EPOLLERR) != 0) event_mask |= (1 << kErrorEvent); 226 if ((events & EPOLLERR) != 0) event_mask |= (1 << kErrorEvent);
252 if (event_mask == 0) event_mask |= (1 << kInEvent); 227 if (event_mask == 0) event_mask |= (1 << kInEvent);
253 } 228 }
254 } else { 229 } else {
255 // Prioritize data events over close and error events. 230 // Prioritize data events over close and error events.
256 if ((events & EPOLLIN) != 0) { 231 if ((events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP)) != 0) {
257 if (FDUtils::AvailableBytes(sd->fd()) != 0) { 232 // If we have EPOLLIN and we have available bytes, report that.
233 if ((events & EPOLLIN) != 0) {
258 event_mask = (1 << kInEvent); 234 event_mask = (1 << kInEvent);
259 } else if ((events & EPOLLHUP) != 0) { 235 }
236 if ((events & (EPOLLHUP | EPOLLRDHUP)) != 0) {
260 // If both EPOLLHUP and EPOLLERR are reported treat it as an 237 // If both EPOLLHUP and EPOLLERR are reported treat it as an
261 // error. 238 // error.
262 if ((events & EPOLLERR) != 0) { 239 if ((events & EPOLLERR) != 0) {
263 event_mask = (1 << kErrorEvent); 240 event_mask = (1 << kErrorEvent);
264 } else { 241 } else {
265 event_mask = (1 << kCloseEvent); 242 event_mask |= (1 << kCloseEvent);
266 } 243 }
267 sd->MarkClosedRead();
268 } else if ((events & EPOLLERR) != 0) { 244 } else if ((events & EPOLLERR) != 0) {
269 event_mask = (1 << kErrorEvent); 245 event_mask = (1 << kErrorEvent);
270 } else {
271 if (sd->IsPipe()) {
272 // When reading from stdin (either from a terminal or piped
273 // input) treat EPOLLIN with 0 available bytes as
274 // end-of-file.
275 if (sd->fd() == STDIN_FILENO) {
276 event_mask = (1 << kCloseEvent);
277 sd->MarkClosedRead();
278 }
279 } else {
280 // If EPOLLIN is set with no available data and no EPOLLHUP use
281 // recv to peek for whether the other end of the socket
282 // actually closed.
283 char buffer;
284 ssize_t bytesPeeked =
285 TEMP_FAILURE_RETRY(recv(sd->fd(), &buffer, 1, MSG_PEEK));
286 ASSERT(EAGAIN == EWOULDBLOCK);
287 if (bytesPeeked == 0) {
288 event_mask = (1 << kCloseEvent);
289 sd->MarkClosedRead();
290 } else if (errno != EWOULDBLOCK) {
291 const int kBufferSize = 1024;
292 char error_message[kBufferSize];
293 strerror_r(errno, error_message, kBufferSize);
294 Log::PrintErr("Error recv: %s\n", error_message);
295 }
296 }
297 }
298 }
299
300 // On pipes EPOLLHUP is reported without EPOLLIN when there is no
301 // more data to read.
302 if (sd->IsPipe()) {
303 if (((events & EPOLLIN) == 0) &&
304 ((events & EPOLLHUP) != 0)) {
305 event_mask = (1 << kCloseEvent);
306 sd->MarkClosedRead();
307 } 246 }
308 } 247 }
309 248
310 if ((events & EPOLLOUT) != 0) { 249 if ((events & EPOLLOUT) != 0) {
311 if ((events & EPOLLERR) != 0) { 250 if ((events & EPOLLERR) != 0) {
312 event_mask = (1 << kErrorEvent); 251 if (!sd->IsPipe()) {
313 sd->MarkClosedWrite(); 252 event_mask = (1 << kErrorEvent);
253 }
314 } else { 254 } else {
315 event_mask |= (1 << kOutEvent); 255 event_mask |= (1 << kOutEvent);
316 } 256 }
317 } 257 }
318 } 258 }
319 259
320 return event_mask; 260 return event_mask;
321 } 261 }
322 262
323 263
324 void EventHandlerImplementation::HandleEvents(struct epoll_event* events, 264 void EventHandlerImplementation::HandleEvents(struct epoll_event* events,
325 int size) { 265 int size) {
326 bool interrupt_seen = false; 266 bool interrupt_seen = false;
327 for (int i = 0; i < size; i++) { 267 for (int i = 0; i < size; i++) {
328 if (events[i].data.ptr == NULL) { 268 if (events[i].data.ptr == NULL) {
329 interrupt_seen = true; 269 interrupt_seen = true;
330 } else { 270 } else {
331 SocketData* sd = reinterpret_cast<SocketData*>(events[i].data.ptr); 271 SocketData* sd = reinterpret_cast<SocketData*>(events[i].data.ptr);
332 intptr_t event_mask = GetPollEvents(events[i].events, sd); 272 intptr_t event_mask = GetPollEvents(events[i].events, sd);
333 if (event_mask != 0) { 273 if (event_mask != 0) {
334 // Unregister events for the file descriptor. Events will be
335 // registered again when the current event has been handled in
336 // Dart code.
337 RemoveFromEpollInstance(epoll_fd_, sd);
338 Dart_Port port = sd->port(); 274 Dart_Port port = sd->port();
339 ASSERT(port != 0); 275 ASSERT(port != 0);
340 DartUtils::PostInt32(port, event_mask); 276 DartUtils::PostInt32(port, event_mask);
341 } 277 }
342 } 278 }
343 } 279 }
344 if (interrupt_seen) { 280 if (interrupt_seen) {
345 // Handle after socket events, so we avoid closing a socket before we handle 281 // Handle after socket events, so we avoid closing a socket before we handle
346 // the current events. 282 // the current events.
347 HandleInterruptFd(); 283 HandleInterruptFd();
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 363
428 uint32_t EventHandlerImplementation::GetHashmapHashFromFd(intptr_t fd) { 364 uint32_t EventHandlerImplementation::GetHashmapHashFromFd(intptr_t fd) {
429 // The hashmap does not support keys with value 0. 365 // The hashmap does not support keys with value 0.
430 return dart::Utils::WordHash(fd + 1); 366 return dart::Utils::WordHash(fd + 1);
431 } 367 }
432 368
433 } // namespace bin 369 } // namespace bin
434 } // namespace dart 370 } // namespace dart
435 371
436 #endif // defined(TARGET_OS_ANDROID) 372 #endif // defined(TARGET_OS_ANDROID)
OLDNEW
« no previous file with comments | « runtime/bin/eventhandler_android.h ('k') | runtime/bin/eventhandler_linux.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698