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

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

Issue 104803005: Use timerfd to handler timeouts on Linux. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Close timer fd. Created 7 years 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_linux.h ('k') | sdk/lib/io/timer_impl.dart » ('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_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
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
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
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
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)
OLDNEW
« no previous file with comments | « runtime/bin/eventhandler_linux.h ('k') | sdk/lib/io/timer_impl.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698