Chromium Code Reviews| 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_LINUX) | 6 #if defined(TARGET_OS_LINUX) |
| 7 | 7 |
| 8 #include "bin/eventhandler.h" | 8 #include "bin/eventhandler.h" |
| 9 | 9 |
| 10 #include <errno.h> // NOLINT | 10 #include <errno.h> // NOLINT |
| 11 #include <pthread.h> // NOLINT | 11 #include <pthread.h> // NOLINT |
| 12 #include <stdio.h> // NOLINT | 12 #include <stdio.h> // NOLINT |
| 13 #include <string.h> // NOLINT | 13 #include <string.h> // NOLINT |
| 14 #include <sys/epoll.h> // NOLINT | 14 #include <sys/epoll.h> // NOLINT |
| 15 #include <sys/stat.h> // NOLINT | 15 #include <sys/stat.h> // NOLINT |
| 16 #include <sys/timerfd.h> // NOLINT | |
| 16 #include <unistd.h> // NOLINT | 17 #include <unistd.h> // NOLINT |
| 17 #include <fcntl.h> // NOLINT | 18 #include <fcntl.h> // NOLINT |
| 18 | 19 |
| 19 #include "bin/dartutils.h" | 20 #include "bin/dartutils.h" |
| 20 #include "bin/fdutils.h" | 21 #include "bin/fdutils.h" |
| 21 #include "bin/log.h" | 22 #include "bin/log.h" |
| 22 #include "bin/utils.h" | 23 #include "bin/utils.h" |
| 23 #include "platform/hashmap.h" | 24 #include "platform/hashmap.h" |
| 24 #include "platform/thread.h" | 25 #include "platform/thread.h" |
| 25 #include "platform/utils.h" | 26 #include "platform/utils.h" |
| 26 | 27 |
| 27 | 28 |
| 28 namespace dart { | 29 namespace dart { |
| 29 namespace bin { | 30 namespace bin { |
| 30 | 31 |
| 31 static const int kInterruptMessageSize = sizeof(InterruptMessage); | 32 static const int kInterruptMessageSize = sizeof(InterruptMessage); |
| 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() { | 37 intptr_t SocketData::GetPollEvents() { |
| 38 // Do not ask for EPOLLERR and EPOLLHUP explicitly as they are | 38 // Do not ask for EPOLLERR and EPOLLHUP explicitly as they are |
| 39 // triggered anyway. | 39 // triggered anyway. |
| 40 intptr_t events = 0; | 40 intptr_t events = 0; |
| 41 if (!IsClosedRead()) { | 41 if (!IsClosedRead()) { |
| 42 if ((mask_ & (1 << kInEvent)) != 0) { | 42 if ((mask_ & (1 << kInEvent)) != 0) { |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 127 struct epoll_event event; | 127 struct epoll_event event; |
| 128 event.events = EPOLLIN; | 128 event.events = EPOLLIN; |
| 129 event.data.ptr = NULL; | 129 event.data.ptr = NULL; |
| 130 int status = TEMP_FAILURE_RETRY(epoll_ctl(epoll_fd_, | 130 int status = TEMP_FAILURE_RETRY(epoll_ctl(epoll_fd_, |
| 131 EPOLL_CTL_ADD, | 131 EPOLL_CTL_ADD, |
| 132 interrupt_fds_[0], | 132 interrupt_fds_[0], |
| 133 &event)); | 133 &event)); |
| 134 if (status == -1) { | 134 if (status == -1) { |
| 135 FATAL("Failed adding interrupt fd to epoll instance"); | 135 FATAL("Failed adding interrupt fd to epoll instance"); |
| 136 } | 136 } |
| 137 timer_fd_ = TEMP_FAILURE_RETRY(timerfd_create(CLOCK_REALTIME, | |
| 138 TFD_NONBLOCK | TFD_CLOEXEC)); | |
| 139 if (epoll_fd_ == -1) { | |
| 140 FATAL("Failed creating timerfd file descriptor"); | |
| 141 } | |
| 142 // Register the timer_fd_ with the epoll instance. | |
| 143 event.events = EPOLLIN; | |
| 144 event.data.fd = timer_fd_; | |
| 145 status = TEMP_FAILURE_RETRY(epoll_ctl(epoll_fd_, | |
| 146 EPOLL_CTL_ADD, | |
| 147 timer_fd_, | |
| 148 &event)); | |
| 149 if (status == -1) { | |
| 150 FATAL("Failed adding timerfd fd to epoll instance"); | |
| 151 } | |
| 137 } | 152 } |
| 138 | 153 |
| 139 | 154 |
| 140 EventHandlerImplementation::~EventHandlerImplementation() { | 155 EventHandlerImplementation::~EventHandlerImplementation() { |
| 141 TEMP_FAILURE_RETRY(close(epoll_fd_)); | 156 TEMP_FAILURE_RETRY(close(epoll_fd_)); |
| 157 TEMP_FAILURE_RETRY(close(timer_fd_)); | |
| 142 TEMP_FAILURE_RETRY(close(interrupt_fds_[0])); | 158 TEMP_FAILURE_RETRY(close(interrupt_fds_[0])); |
| 143 TEMP_FAILURE_RETRY(close(interrupt_fds_[1])); | 159 TEMP_FAILURE_RETRY(close(interrupt_fds_[1])); |
| 144 } | 160 } |
| 145 | 161 |
| 146 | 162 |
| 147 SocketData* EventHandlerImplementation::GetSocketData(intptr_t fd) { | 163 SocketData* EventHandlerImplementation::GetSocketData(intptr_t fd) { |
| 148 ASSERT(fd >= 0); | 164 ASSERT(fd >= 0); |
| 149 HashMap::Entry* entry = socket_map_.Lookup( | 165 HashMap::Entry* entry = socket_map_.Lookup( |
| 150 GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd), true); | 166 GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd), true); |
| 151 ASSERT(entry != NULL); | 167 ASSERT(entry != NULL); |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 182 } | 198 } |
| 183 } | 199 } |
| 184 | 200 |
| 185 | 201 |
| 186 void EventHandlerImplementation::HandleInterruptFd() { | 202 void EventHandlerImplementation::HandleInterruptFd() { |
| 187 const intptr_t MAX_MESSAGES = kInterruptMessageSize; | 203 const intptr_t MAX_MESSAGES = kInterruptMessageSize; |
| 188 InterruptMessage msg[MAX_MESSAGES]; | 204 InterruptMessage msg[MAX_MESSAGES]; |
| 189 ssize_t bytes = TEMP_FAILURE_RETRY( | 205 ssize_t bytes = TEMP_FAILURE_RETRY( |
| 190 read(interrupt_fds_[0], msg, MAX_MESSAGES * kInterruptMessageSize)); | 206 read(interrupt_fds_[0], msg, MAX_MESSAGES * kInterruptMessageSize)); |
| 191 for (ssize_t i = 0; i < bytes / kInterruptMessageSize; i++) { | 207 for (ssize_t i = 0; i < bytes / kInterruptMessageSize; i++) { |
| 192 if (msg[i].id == kTimerId) { | 208 if (msg[i].id == kTimerId) { |
|
Søren Gjesse
2013/12/05 07:39:34
With this approach do we even need to send this th
Anders Johnsen
2013/12/05 09:18:28
The alternative is to have a FD per isolate, but t
| |
| 193 timeout_queue_.UpdateTimeout(msg[i].dart_port, msg[i].data); | 209 timeout_queue_.UpdateTimeout(msg[i].dart_port, msg[i].data); |
| 210 struct itimerspec it; | |
| 211 memset(&it, 0, sizeof(it)); | |
| 212 if (timeout_queue_.HasTimeout()) { | |
| 213 int64_t millis = timeout_queue_.CurrentTimeout(); | |
| 214 it.it_value.tv_sec = millis / 1000; | |
| 215 it.it_value.tv_nsec = (millis % 1000) * 1000000; | |
| 216 } | |
| 217 timerfd_settime(timer_fd_, TFD_TIMER_ABSTIME, &it, NULL); | |
|
Søren Gjesse
2013/12/05 07:39:34
If the abs time set here has just passed will the
Anders Johnsen
2013/12/05 09:18:28
Yes, from spec:
"If the specified absolute time
| |
| 194 } else if (msg[i].id == kShutdownId) { | 218 } else if (msg[i].id == kShutdownId) { |
| 195 shutdown_ = true; | 219 shutdown_ = true; |
| 196 } else { | 220 } else { |
| 197 SocketData* sd = GetSocketData(msg[i].id); | 221 SocketData* sd = GetSocketData(msg[i].id); |
| 198 if ((msg[i].data & (1 << kShutdownReadCommand)) != 0) { | 222 if ((msg[i].data & (1 << kShutdownReadCommand)) != 0) { |
| 199 ASSERT(msg[i].data == (1 << kShutdownReadCommand)); | 223 ASSERT(msg[i].data == (1 << kShutdownReadCommand)); |
| 200 // Close the socket for reading. | 224 // Close the socket for reading. |
| 201 sd->ShutdownRead(); | 225 sd->ShutdownRead(); |
| 202 UpdateEpollInstance(epoll_fd_, sd); | 226 UpdateEpollInstance(epoll_fd_, sd); |
| 203 } else if ((msg[i].data & (1 << kShutdownWriteCommand)) != 0) { | 227 } else if ((msg[i].data & (1 << kShutdownWriteCommand)) != 0) { |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 331 return event_mask; | 355 return event_mask; |
| 332 } | 356 } |
| 333 | 357 |
| 334 | 358 |
| 335 void EventHandlerImplementation::HandleEvents(struct epoll_event* events, | 359 void EventHandlerImplementation::HandleEvents(struct epoll_event* events, |
| 336 int size) { | 360 int size) { |
| 337 bool interrupt_seen = false; | 361 bool interrupt_seen = false; |
| 338 for (int i = 0; i < size; i++) { | 362 for (int i = 0; i < size; i++) { |
| 339 if (events[i].data.ptr == NULL) { | 363 if (events[i].data.ptr == NULL) { |
| 340 interrupt_seen = true; | 364 interrupt_seen = true; |
| 365 } else if (events[i].data.fd == timer_fd_) { | |
| 366 int64_t val; | |
| 367 VOID_TEMP_FAILURE_RETRY(read(timer_fd_, &val, 8)); | |
|
Søren Gjesse
2013/12/05 07:39:34
Should we have a constant for '8' here just to ind
Anders Johnsen
2013/12/05 09:18:28
I'll use sizeof val.
| |
| 368 if (timeout_queue_.HasTimeout()) { | |
| 369 DartUtils::PostNull(timeout_queue_.CurrentPort()); | |
| 370 timeout_queue_.RemoveCurrent(); | |
| 371 } | |
| 341 } else { | 372 } else { |
| 342 SocketData* sd = reinterpret_cast<SocketData*>(events[i].data.ptr); | 373 SocketData* sd = reinterpret_cast<SocketData*>(events[i].data.ptr); |
| 343 intptr_t event_mask = GetPollEvents(events[i].events, sd); | 374 intptr_t event_mask = GetPollEvents(events[i].events, sd); |
| 344 if (event_mask == 0) { | 375 if (event_mask == 0) { |
| 345 // Event not handled, re-add to epoll. | 376 // Event not handled, re-add to epoll. |
| 346 UpdateEpollInstance(epoll_fd_, sd); | 377 UpdateEpollInstance(epoll_fd_, sd); |
| 347 } else { | 378 } else { |
| 348 Dart_Port port = sd->port(); | 379 Dart_Port port = sd->port(); |
| 349 ASSERT(port != 0); | 380 ASSERT(port != 0); |
| 350 DartUtils::PostInt32(port, event_mask); | 381 DartUtils::PostInt32(port, event_mask); |
| 351 } | 382 } |
| 352 } | 383 } |
| 353 } | 384 } |
| 354 if (interrupt_seen) { | 385 if (interrupt_seen) { |
| 355 // Handle after socket events, so we avoid closing a socket before we handle | 386 // Handle after socket events, so we avoid closing a socket before we handle |
| 356 // the current events. | 387 // the current events. |
| 357 HandleInterruptFd(); | 388 HandleInterruptFd(); |
| 358 } | 389 } |
| 359 } | 390 } |
| 360 | 391 |
| 361 | 392 |
| 362 int64_t EventHandlerImplementation::GetTimeout() { | |
| 363 if (!timeout_queue_.HasTimeout()) { | |
| 364 return kInfinityTimeout; | |
| 365 } | |
| 366 int64_t millis = timeout_queue_.CurrentTimeout() - | |
| 367 TimerUtils::GetCurrentTimeMilliseconds(); | |
| 368 return (millis < 0) ? 0 : millis; | |
| 369 } | |
| 370 | |
| 371 | |
| 372 void EventHandlerImplementation::HandleTimeout() { | |
| 373 if (timeout_queue_.HasTimeout()) { | |
| 374 int64_t millis = timeout_queue_.CurrentTimeout() - | |
| 375 TimerUtils::GetCurrentTimeMilliseconds(); | |
| 376 if (millis <= 0) { | |
| 377 DartUtils::PostNull(timeout_queue_.CurrentPort()); | |
| 378 // Remove current from queue. | |
| 379 timeout_queue_.RemoveCurrent(); | |
| 380 } | |
| 381 } | |
| 382 } | |
| 383 | |
| 384 | |
| 385 void EventHandlerImplementation::Poll(uword args) { | 393 void EventHandlerImplementation::Poll(uword args) { |
| 386 static const intptr_t kMaxEvents = 16; | 394 static const intptr_t kMaxEvents = 16; |
| 387 struct epoll_event events[kMaxEvents]; | 395 struct epoll_event events[kMaxEvents]; |
| 388 EventHandler* handler = reinterpret_cast<EventHandler*>(args); | 396 EventHandler* handler = reinterpret_cast<EventHandler*>(args); |
| 389 EventHandlerImplementation* handler_impl = &handler->delegate_; | 397 EventHandlerImplementation* handler_impl = &handler->delegate_; |
| 390 ASSERT(handler_impl != NULL); | 398 ASSERT(handler_impl != NULL); |
| 391 while (!handler_impl->shutdown_) { | 399 while (!handler_impl->shutdown_) { |
| 392 int64_t millis = handler_impl->GetTimeout(); | |
| 393 ASSERT(millis == kInfinityTimeout || millis >= 0); | |
| 394 if (millis > kMaxInt32) millis = kMaxInt32; | |
| 395 intptr_t result = TEMP_FAILURE_RETRY(epoll_wait(handler_impl->epoll_fd_, | 400 intptr_t result = TEMP_FAILURE_RETRY(epoll_wait(handler_impl->epoll_fd_, |
| 396 events, | 401 events, |
| 397 kMaxEvents, | 402 kMaxEvents, |
| 398 millis)); | 403 -1)); |
|
Søren Gjesse
2013/12/05 07:39:34
Is there a constant for infinite?
Anders Johnsen
2013/12/05 09:18:28
-1 is special-case for epoll_wait, to wait forever
| |
| 399 ASSERT(EAGAIN == EWOULDBLOCK); | 404 ASSERT(EAGAIN == EWOULDBLOCK); |
| 400 if (result == -1) { | 405 if (result <= 0) { |
| 401 if (errno != EWOULDBLOCK) { | 406 if (errno != EWOULDBLOCK) { |
| 402 perror("Poll failed"); | 407 perror("Poll failed"); |
| 403 } | 408 } |
| 404 } else if (result == 0) { | |
| 405 handler_impl->HandleTimeout(); | |
| 406 } else { | 409 } else { |
| 407 handler_impl->HandleEvents(events, result); | 410 handler_impl->HandleEvents(events, result); |
| 408 } | 411 } |
| 409 } | 412 } |
| 410 delete handler; | 413 delete handler; |
| 411 } | 414 } |
| 412 | 415 |
| 413 | 416 |
| 414 void EventHandlerImplementation::Start(EventHandler* handler) { | 417 void EventHandlerImplementation::Start(EventHandler* handler) { |
| 415 int result = dart::Thread::Start(&EventHandlerImplementation::Poll, | 418 int result = dart::Thread::Start(&EventHandlerImplementation::Poll, |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 440 | 443 |
| 441 uint32_t EventHandlerImplementation::GetHashmapHashFromFd(intptr_t fd) { | 444 uint32_t EventHandlerImplementation::GetHashmapHashFromFd(intptr_t fd) { |
| 442 // The hashmap does not support keys with value 0. | 445 // The hashmap does not support keys with value 0. |
| 443 return dart::Utils::WordHash(fd + 1); | 446 return dart::Utils::WordHash(fd + 1); |
| 444 } | 447 } |
| 445 | 448 |
| 446 } // namespace bin | 449 } // namespace bin |
| 447 } // namespace dart | 450 } // namespace dart |
| 448 | 451 |
| 449 #endif // defined(TARGET_OS_LINUX) | 452 #endif // defined(TARGET_OS_LINUX) |
| OLD | NEW |