diff --git a/runtime/bin/eventhandler_fuchsia.cc b/runtime/bin/eventhandler_fuchsia.cc index ff03f14ab9e..0d52f55cae0 100644 --- a/runtime/bin/eventhandler_fuchsia.cc +++ b/runtime/bin/eventhandler_fuchsia.cc @@ -13,18 +13,146 @@ #include #include +#include "bin/log.h" #include "bin/thread.h" #include "bin/utils.h" +#if defined(EVENTHANDLER_LOGGING) +#define LOG_ERR(msg, ...) Log::PrintErr(msg, ##__VA_ARGS__) +#define LOG_INFO(msg, ...) Log::Print(msg, ##__VA_ARGS__) +#else +#define LOG_ERR(msg, ...) +#define LOG_INFO(msg, ...) +#endif // defined(EVENTHANDLER_LOGGING) + namespace dart { namespace bin { +MagentaWaitManyInfo::MagentaWaitManyInfo() + : capacity_(kInitialCapacity), + size_(0) { + descriptor_infos_ = static_cast( + malloc(kInitialCapacity * sizeof(*descriptor_infos_))); + if (descriptor_infos_ == NULL) { + FATAL("Failed to allocate descriptor_infos array"); + } + handles_ = static_cast( + malloc(kInitialCapacity * sizeof(*handles_))); + if (handles_ == NULL) { + FATAL("Failed to allocate handles array"); + } + signals_ = static_cast( + malloc(kInitialCapacity * sizeof(*signals_))); + if (signals_ == NULL) { + FATAL("Failed to allocate signals array"); + } + signals_states_ = static_cast( + malloc(kInitialCapacity * sizeof(*signals_states_))); + if (signals_states_ == NULL) { + FATAL("Failed to allocate signals_states array"); + } +} + + +MagentaWaitManyInfo::~MagentaWaitManyInfo() { + free(descriptor_infos_); + free(handles_); + free(signals_); + free(signals_states_); +} + + +void MagentaWaitManyInfo::AddHandle(mx_handle_t handle, + mx_signals_t signals, + DescriptorInfo* di) { +#if defined(DEBUG) + // Check that the handle is not already in the list. + for (intptr_t i = 0; i < size_; i++) { + if (handles_[i] == handle) { + FATAL("The handle is already in the list!"); + } + } +#endif + intptr_t new_size = size_ + 1; + GrowArraysIfNeeded(new_size); + descriptor_infos_[size_] = di; + handles_[size_] = handle; + signals_[size_] = signals; + signals_states_[size_].satisfied = MX_SIGNAL_NONE; + signals_states_[size_].satisfiable = MX_SIGNAL_NONE; + size_ = new_size; + LOG_INFO("AddHandle(%ld, %ld, %p), size = %ld\n", handle, signals, di, size_); +} + + +void MagentaWaitManyInfo::RemoveHandle(mx_handle_t handle) { + intptr_t idx; + for (idx = 1; idx < size_; idx++) { + if (handle == handles_[idx]) { + break; + } + } + if (idx == size_) { + FATAL("Handle is not in the list!"); + } + + if (idx != (size_ - 1)) { + descriptor_infos_[idx] = descriptor_infos_[size_ - 1]; + handles_[idx] = handles_[size_ - 1]; + signals_[idx] = signals_[size_ - 1]; + signals_states_[idx] = signals_states_[size_ - 1]; + } + descriptor_infos_[size_ - 1] = NULL; + handles_[size_ - 1] = MX_HANDLE_INVALID; + signals_[size_ - 1] = MX_SIGNAL_NONE; + signals_states_[size_ - 1].satisfied = MX_SIGNAL_NONE; + signals_states_[size_ - 1].satisfiable = MX_SIGNAL_NONE; + size_ = size_ - 1; + LOG_INFO("RemoveHandle(%ld), size = %ld\n", handle, size_); +} + + +void MagentaWaitManyInfo::GrowArraysIfNeeded(intptr_t desired_size) { + if (desired_size < capacity_) { + return; + } + intptr_t new_capacity = desired_size + (desired_size >> 1); + descriptor_infos_ = static_cast( + realloc(descriptor_infos_, new_capacity * sizeof(*descriptor_infos_))); + if (descriptor_infos_ == NULL) { + FATAL("Failed to grow descriptor_infos array"); + } + handles_ = static_cast( + realloc(handles_, new_capacity * sizeof(*handles_))); + if (handles_ == NULL) { + FATAL("Failed to grow handles array"); + } + signals_ = static_cast( + realloc(signals_, new_capacity * sizeof(*signals_))); + if (signals_ == NULL) { + FATAL("Failed to grow signals array"); + } + signals_states_ = static_cast( + realloc(signals_states_, new_capacity * sizeof(*signals_states_))); + if (signals_states_ == NULL) { + FATAL("Failed to grow signals_states array"); + } + capacity_ = new_capacity; + LOG_INFO("GrowArraysIfNeeded(%ld), capacity = %ld\n", + desired_size, capacity_); +} + + EventHandlerImplementation::EventHandlerImplementation() { mx_status_t status = mx_msgpipe_create(interrupt_handles_, 0); if (status != NO_ERROR) { FATAL1("mx_msgpipe_create failed: %s\n", mx_status_get_string(status)); } shutdown_ = false; + info_.AddHandle(interrupt_handles_[0], + MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED, + NULL); + LOG_INFO("EventHandlerImplementation initialized\n"); } @@ -37,6 +165,7 @@ EventHandlerImplementation::~EventHandlerImplementation() { if (status != NO_ERROR) { FATAL1("mx_handle_close failed: %s\n", mx_status_get_string(status)); } + LOG_INFO("EventHandlerImplementation destroyed\n"); } @@ -53,10 +182,12 @@ void EventHandlerImplementation::WakeupHandler(intptr_t id, if (status != NO_ERROR) { FATAL1("mx_msgpipe_write failed: %s\n", mx_status_get_string(status)); } + LOG_INFO("WakeupHandler(%ld, %ld, %lld)\n", id, dart_port, data); } void EventHandlerImplementation::HandleInterruptFd() { + LOG_INFO("HandleInterruptFd entry\n"); InterruptMessage msg; uint32_t bytes = kInterruptMessageSize; mx_status_t status; @@ -68,10 +199,14 @@ void EventHandlerImplementation::HandleInterruptFd() { } ASSERT(bytes == kInterruptMessageSize); if (msg.id == kTimerId) { + LOG_INFO("HandleInterruptFd read timer update\n"); timeout_queue_.UpdateTimeout(msg.dart_port, msg.data); } else if (msg.id == kShutdownId) { + LOG_INFO("HandleInterruptFd read shutdown\n"); shutdown_ = true; } else { + // TODO(zra): Handle commands to add and remove handles from the + // MagentaWaitManyInfo. UNIMPLEMENTED(); } } @@ -80,13 +215,32 @@ void EventHandlerImplementation::HandleInterruptFd() { if (status != ERR_SHOULD_WAIT) { FATAL1("mx_msgpipe_read failed: %s\n", mx_status_get_string(status)); } + LOG_INFO("HandleInterruptFd exit\n"); } void EventHandlerImplementation::HandleEvents() { - // TODO(zra): Handle events from other handles. At the moment we are only - // interrupted when there is a message on interrupt_handles_[0]. - HandleInterruptFd(); + LOG_INFO("HandleEvents entry\n"); + for (intptr_t i = 1; i < info_.size(); i++) { + if (info_.signals_states()[i].satisfied != MX_SIGNAL_NONE) { + // Only the control handle has no descriptor info. + ASSERT(info_.descriptor_infos()[i] != NULL); + ASSERT(info_.handles()[i] != interrupt_handles_[0]); + // TODO(zra): Handle events on other handles. At the moment we are + // only interrupted when there is a message on interrupt_handles_[0]. + UNIMPLEMENTED(); + } + } + + if ((info_.signals_states()[0].satisfied & MX_SIGNAL_PEER_CLOSED) != 0) { + FATAL("EventHandlerImplementation::Poll: Unexpected peer closed\n"); + } + if ((info_.signals_states()[0].satisfied & MX_SIGNAL_READABLE) != 0) { + LOG_INFO("HandleEvents interrupt_handles_[0] readable\n"); + HandleInterruptFd(); + } else { + LOG_INFO("HandleEvents interrupt_handles_[0] not readable\n"); + } } @@ -120,28 +274,30 @@ void EventHandlerImplementation::Poll(uword args) { while (!handler_impl->shutdown_) { int64_t millis = handler_impl->GetTimeout(); ASSERT((millis == kInfinityTimeout) || (millis >= 0)); - mx_time_t timeout = millis * kMicrosecondsPerMillisecond * kNanosecondsPerMicrosecond; - mx_signals_state_t signals_state; - mx_status_t status = mx_handle_wait_one( - handler_impl->interrupt_handles_[0], - MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED, + const MagentaWaitManyInfo& info = handler_impl->info(); + uint32_t result_index; + LOG_INFO("mx_handle_wait_many(%ld, %p, %p, %lld, %p, %p)\n", + info.size(), info.handles(), info.signals(), timeout, &result_index, + info.signals_states()); + mx_status_t status = mx_handle_wait_many( + info.size(), + info.handles(), + info.signals(), timeout, - &signals_state); + &result_index, + info.signals_states()); if ((status != NO_ERROR) && (status != ERR_TIMED_OUT)) { - FATAL1("mx_handle_wait_one failed: %s\n", mx_status_get_string(status)); + FATAL1("mx_handle_wait_many failed: %s\n", mx_status_get_string(status)); } else { + LOG_INFO("mx_handle_wait_many returned: %ld\n", status); handler_impl->HandleTimeout(); - if ((signals_state.satisfied & MX_SIGNAL_READABLE) != 0) { - handler_impl->HandleEvents(); - } - if ((signals_state.satisfied & MX_SIGNAL_PEER_CLOSED) != 0) { - FATAL("EventHandlerImplementation::Poll: Unexpected peer closed\n"); - } + handler_impl->HandleEvents(); } } handler->NotifyShutdownDone(); + LOG_INFO("EventHandlerImplementation notifying about shutdown\n"); } diff --git a/runtime/bin/eventhandler_fuchsia.h b/runtime/bin/eventhandler_fuchsia.h index 01309923247..b168c6208be 100644 --- a/runtime/bin/eventhandler_fuchsia.h +++ b/runtime/bin/eventhandler_fuchsia.h @@ -9,11 +9,82 @@ #error Do not include eventhandler_fuchsia.h directly; use eventhandler.h instead. #endif +#include #include +#include "platform/signal_blocker.h" + namespace dart { namespace bin { +class DescriptorInfo : public DescriptorInfoBase { + public: + explicit DescriptorInfo(intptr_t fd) : DescriptorInfoBase(fd) { } + + virtual ~DescriptorInfo() { } + + virtual void Close() { + VOID_TEMP_FAILURE_RETRY(close(fd_)); + fd_ = -1; + } + + private: + DISALLOW_COPY_AND_ASSIGN(DescriptorInfo); +}; + +class DescriptorInfoSingle + : public DescriptorInfoSingleMixin { + public: + explicit DescriptorInfoSingle(intptr_t fd) + : DescriptorInfoSingleMixin(fd, false) {} + virtual ~DescriptorInfoSingle() {} + + private: + DISALLOW_COPY_AND_ASSIGN(DescriptorInfoSingle); +}; + +class DescriptorInfoMultiple + : public DescriptorInfoMultipleMixin { + public: + explicit DescriptorInfoMultiple(intptr_t fd) + : DescriptorInfoMultipleMixin(fd, false) {} + virtual ~DescriptorInfoMultiple() {} + + private: + DISALLOW_COPY_AND_ASSIGN(DescriptorInfoMultiple); +}; + +// Information needed to call mx_handle_wait_many(), and to handle events. +class MagentaWaitManyInfo { + public: + MagentaWaitManyInfo(); + ~MagentaWaitManyInfo(); + + intptr_t capacity() const { return capacity_; } + intptr_t size() const { return size_; } + DescriptorInfo** descriptor_infos() const { return descriptor_infos_; } + mx_handle_t* handles() const { return handles_; } + mx_signals_t* signals() const { return signals_; } + mx_signals_state_t* signals_states() const { return signals_states_; } + + void AddHandle(mx_handle_t handle, mx_signals_t signals, DescriptorInfo* di); + void RemoveHandle(mx_handle_t handle); + + private: + static const intptr_t kInitialCapacity = 32; + + void GrowArraysIfNeeded(intptr_t desired_size); + + intptr_t capacity_; + intptr_t size_; + DescriptorInfo** descriptor_infos_; + mx_handle_t* handles_; + mx_signals_t* signals_; + mx_signals_state_t* signals_states_; + + DISALLOW_COPY_AND_ASSIGN(MagentaWaitManyInfo); +}; + class EventHandlerImplementation { public: EventHandlerImplementation(); @@ -23,6 +94,8 @@ class EventHandlerImplementation { void Start(EventHandler* handler); void Shutdown(); + const MagentaWaitManyInfo& info() const { return info_; } + private: int64_t GetTimeout() const; void HandleEvents(); @@ -35,6 +108,8 @@ class EventHandlerImplementation { bool shutdown_; mx_handle_t interrupt_handles_[2]; + MagentaWaitManyInfo info_; + DISALLOW_COPY_AND_ASSIGN(EventHandlerImplementation); };