OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 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. |
| 4 |
| 5 #if !defined(DART_IO_DISABLED) |
| 6 |
| 7 #include "platform/globals.h" |
| 8 #if defined(TARGET_OS_FUCHSIA) |
| 9 |
| 10 #include "bin/eventhandler.h" |
| 11 #include "bin/eventhandler_fuchsia.h" |
| 12 |
| 13 #include <magenta/syscalls.h> |
| 14 #include <runtime/status.h> |
| 15 |
| 16 #include "bin/thread.h" |
| 17 #include "bin/utils.h" |
| 18 |
| 19 namespace dart { |
| 20 namespace bin { |
| 21 |
| 22 EventHandlerImplementation::EventHandlerImplementation() { |
| 23 mx_status_t status = mx_message_pipe_create(interrupt_handles_, 0); |
| 24 if (status != NO_ERROR) { |
| 25 FATAL1("mx_message_pipe_create failed: %s\n", mx_strstatus(status)); |
| 26 } |
| 27 } |
| 28 |
| 29 |
| 30 EventHandlerImplementation::~EventHandlerImplementation() { |
| 31 mx_status_t status = mx_handle_close(interrupt_handles_[0]); |
| 32 if (status != NO_ERROR) { |
| 33 FATAL1("mx_handle_close failed: %s\n", mx_strstatus(status)); |
| 34 } |
| 35 status = mx_handle_close(interrupt_handles_[1]); |
| 36 if (status != NO_ERROR) { |
| 37 FATAL1("mx_handle_close failed: %s\n", mx_strstatus(status)); |
| 38 } |
| 39 } |
| 40 |
| 41 |
| 42 void EventHandlerImplementation::WakeupHandler(intptr_t id, |
| 43 Dart_Port dart_port, |
| 44 int64_t data) { |
| 45 InterruptMessage msg; |
| 46 msg.id = id; |
| 47 msg.dart_port = dart_port; |
| 48 msg.data = data; |
| 49 |
| 50 mx_status_t status = |
| 51 mx_message_write(interrupt_handles_[1], &msg, sizeof(msg), NULL, 0, 0); |
| 52 if (status != NO_ERROR) { |
| 53 FATAL1("mx_message_write failed: %s\n", mx_strstatus(status)); |
| 54 } |
| 55 } |
| 56 |
| 57 |
| 58 void EventHandlerImplementation::HandleInterruptFd() { |
| 59 InterruptMessage msg; |
| 60 uint32_t bytes = kInterruptMessageSize; |
| 61 mx_status_t status; |
| 62 while (true) { |
| 63 status = mx_message_read( |
| 64 interrupt_handles_[0], &msg, &bytes, NULL, NULL, 0); |
| 65 if (status != NO_ERROR) { |
| 66 break; |
| 67 } |
| 68 ASSERT(bytes == kInterruptMessageSize); |
| 69 if (msg.id == kTimerId) { |
| 70 timeout_queue_.UpdateTimeout(msg.dart_port, msg.data); |
| 71 } else if (msg.id == kShutdownId) { |
| 72 shutdown_ = true; |
| 73 } else { |
| 74 UNIMPLEMENTED(); |
| 75 } |
| 76 } |
| 77 // status == ERR_BAD_STATE when we try to read and there are no messages |
| 78 // available, so it is an error if we get here and status != ERR_BAD_STATE. |
| 79 if (status != ERR_BAD_STATE) { |
| 80 FATAL1("mx_message_read failed: %s\n", mx_strstatus(status)); |
| 81 } |
| 82 } |
| 83 |
| 84 |
| 85 void EventHandlerImplementation::HandleEvents() { |
| 86 // TODO(zra): Handle events from other handles. At the moment we are only |
| 87 // interrupted when there is a message on interrupt_handles_[0]. |
| 88 HandleInterruptFd(); |
| 89 } |
| 90 |
| 91 |
| 92 int64_t EventHandlerImplementation::GetTimeout() const { |
| 93 if (!timeout_queue_.HasTimeout()) { |
| 94 return kInfinityTimeout; |
| 95 } |
| 96 int64_t millis = timeout_queue_.CurrentTimeout() - |
| 97 TimerUtils::GetCurrentMonotonicMillis(); |
| 98 return (millis < 0) ? 0 : millis; |
| 99 } |
| 100 |
| 101 |
| 102 void EventHandlerImplementation::HandleTimeout() { |
| 103 if (timeout_queue_.HasTimeout()) { |
| 104 int64_t millis = timeout_queue_.CurrentTimeout() - |
| 105 TimerUtils::GetCurrentMonotonicMillis(); |
| 106 if (millis <= 0) { |
| 107 DartUtils::PostNull(timeout_queue_.CurrentPort()); |
| 108 timeout_queue_.RemoveCurrent(); |
| 109 } |
| 110 } |
| 111 } |
| 112 |
| 113 |
| 114 void EventHandlerImplementation::Poll(uword args) { |
| 115 EventHandler* handler = reinterpret_cast<EventHandler*>(args); |
| 116 EventHandlerImplementation* handler_impl = &handler->delegate_; |
| 117 ASSERT(handler_impl != NULL); |
| 118 |
| 119 while (!handler_impl->shutdown_) { |
| 120 int64_t millis = handler_impl->GetTimeout(); |
| 121 ASSERT((millis == kInfinityTimeout) || (millis >= 0)); |
| 122 |
| 123 mx_time_t timeout = |
| 124 millis * kMicrosecondsPerMillisecond * kNanosecondsPerMicrosecond; |
| 125 mx_signals_state_t signals_state; |
| 126 mx_status_t status = mx_handle_wait_one( |
| 127 handler_impl->interrupt_handles_[0], |
| 128 MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED, |
| 129 timeout, |
| 130 &signals_state); |
| 131 if ((status != NO_ERROR) && (status != ERR_TIMED_OUT)) { |
| 132 FATAL1("mx_handle_wait_one failed: %s\n", mx_strstatus(status)); |
| 133 } else { |
| 134 handler_impl->HandleTimeout(); |
| 135 if ((signals_state.satisfied & MX_SIGNAL_READABLE) != 0) { |
| 136 handler_impl->HandleEvents(); |
| 137 } |
| 138 if ((signals_state.satisfied & MX_SIGNAL_PEER_CLOSED) != 0) { |
| 139 FATAL("EventHandlerImplementation::Poll: Unexpected peer closed\n"); |
| 140 } |
| 141 } |
| 142 } |
| 143 handler->NotifyShutdownDone(); |
| 144 } |
| 145 |
| 146 |
| 147 void EventHandlerImplementation::Start(EventHandler* handler) { |
| 148 int result = Thread::Start(&EventHandlerImplementation::Poll, |
| 149 reinterpret_cast<uword>(handler)); |
| 150 if (result != 0) { |
| 151 FATAL1("Failed to start event handler thread %d", result); |
| 152 } |
| 153 } |
| 154 |
| 155 |
| 156 void EventHandlerImplementation::Shutdown() { |
| 157 SendData(kShutdownId, 0, 0); |
| 158 } |
| 159 |
| 160 |
| 161 void EventHandlerImplementation::SendData(intptr_t id, |
| 162 Dart_Port dart_port, |
| 163 int64_t data) { |
| 164 WakeupHandler(id, dart_port, data); |
| 165 } |
| 166 |
| 167 } // namespace bin |
| 168 } // namespace dart |
| 169 |
| 170 #endif // defined(TARGET_OS_FUCHSIA) |
| 171 |
| 172 #endif // !defined(DART_IO_DISABLED) |
OLD | NEW |