| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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) |
| OLD | NEW |