Index: runtime/bin/process_fuchsia.cc |
diff --git a/runtime/bin/process_fuchsia.cc b/runtime/bin/process_fuchsia.cc |
index 732c29e1214657e9844fb14c5fda4f99a98ac34f..ab7d5325a9488a7e1547c26fdddb8547d7c1e368 100644 |
--- a/runtime/bin/process_fuchsia.cc |
+++ b/runtime/bin/process_fuchsia.cc |
@@ -29,6 +29,7 @@ |
#include <unistd.h> |
#include "bin/dartutils.h" |
+#include "bin/eventhandler.h" |
#include "bin/fdutils.h" |
#include "bin/lockers.h" |
#include "bin/log.h" |
@@ -454,55 +455,19 @@ int64_t Process::MaxRSS() { |
} |
-static bool ProcessWaitCleanup(intptr_t out, |
- intptr_t err, |
- intptr_t exit_event) { |
- int e = errno; |
- VOID_NO_RETRY_EXPECTED(close(out)); |
- VOID_NO_RETRY_EXPECTED(close(err)); |
- VOID_NO_RETRY_EXPECTED(close(exit_event)); |
- errno = e; |
- return false; |
-} |
- |
- |
-class MxioWaitEntry { |
+class IOHandleScope { |
public: |
- MxioWaitEntry() {} |
- ~MxioWaitEntry() { Cancel(); } |
- |
- void Init(int fd) { mxio_ = __mxio_fd_to_io(fd); } |
- |
- void WaitBegin(mx_wait_item_t* wait_item) { |
- if (mxio_ == NULL) { |
- *wait_item = {}; |
- return; |
- } |
- |
- __mxio_wait_begin(mxio_, EPOLLRDHUP | EPOLLIN, &wait_item->handle, |
- &wait_item->waitfor); |
- wait_item->pending = 0; |
- } |
- |
- void WaitEnd(mx_wait_item_t* wait_item, uint32_t* event) { |
- if (mxio_ == NULL) { |
- *event = 0; |
- return; |
- } |
- __mxio_wait_end(mxio_, wait_item->pending, event); |
- } |
- |
- void Cancel() { |
- if (mxio_ != NULL) { |
- __mxio_release(mxio_); |
- } |
- mxio_ = NULL; |
+ explicit IOHandleScope(IOHandle* io_handle) : io_handle_(io_handle) {} |
+ ~IOHandleScope() { |
+ io_handle_->Close(); |
+ io_handle_->Release(); |
} |
private: |
- mxio_t* mxio_ = NULL; |
+ IOHandle* io_handle_; |
- DISALLOW_COPY_AND_ASSIGN(MxioWaitEntry); |
+ DISALLOW_ALLOCATION(); |
+ DISALLOW_COPY_AND_ASSIGN(IOHandleScope); |
}; |
@@ -512,7 +477,18 @@ bool Process::Wait(intptr_t pid, |
intptr_t err, |
intptr_t exit_event, |
ProcessResult* result) { |
- VOID_NO_RETRY_EXPECTED(close(in)); |
+ // input not needed. |
+ IOHandle* in_iohandle = reinterpret_cast<IOHandle*>(in); |
+ in_iohandle->Close(); |
+ in_iohandle->Release(); |
+ in_iohandle = NULL; |
+ |
+ IOHandle* out_iohandle = reinterpret_cast<IOHandle*>(out); |
+ IOHandle* err_iohandle = reinterpret_cast<IOHandle*>(err); |
+ IOHandle* exit_iohandle = reinterpret_cast<IOHandle*>(exit_event); |
+ IOHandleScope out_ioscope(out_iohandle); |
+ IOHandleScope err_ioscope(err_iohandle); |
+ IOHandleScope exit_ioscope(exit_iohandle); |
// There is no return from this function using Dart_PropagateError |
// as memory used by the buffer lists is freed through their |
@@ -524,52 +500,95 @@ bool Process::Wait(intptr_t pid, |
int32_t ints[2]; |
} exit_code_data; |
- constexpr size_t kWaitItemsCount = 3; |
- uint32_t events[kWaitItemsCount]; |
- mx_wait_item_t wait_items[kWaitItemsCount]; |
- size_t active = kWaitItemsCount; |
- |
- MxioWaitEntry entries[kWaitItemsCount]; |
- entries[0].Init(out); |
- entries[1].Init(err); |
- entries[2].Init(exit_event); |
- |
- while (active > 0) { |
- for (size_t i = 0; i < kWaitItemsCount; ++i) { |
- entries[i].WaitBegin(&wait_items[i]); |
- } |
- mx_object_wait_many(wait_items, kWaitItemsCount, MX_TIME_INFINITE); |
- |
- for (size_t i = 0; i < kWaitItemsCount; ++i) { |
- entries[i].WaitEnd(&wait_items[i], &events[i]); |
- } |
+ // Create a port, which is like an epoll() fd on Linux. |
+ mx_handle_t port; |
+ mx_status_t status = mx_port_create(MX_PORT_OPT_V2, &port); |
+ if (status != MX_OK) { |
+ Log::PrintErr("Process::Wait: mx_port_create failed: %s\n", |
+ mx_status_get_string(status)); |
+ return false; |
+ } |
- if ((events[0] & EPOLLIN) != 0) { |
- const intptr_t avail = FDUtils::AvailableBytes(out); |
- if (!out_data.Read(out, avail)) { |
- return ProcessWaitCleanup(out, err, exit_event); |
+ IOHandle* out_tmp = out_iohandle; |
+ IOHandle* err_tmp = err_iohandle; |
+ IOHandle* exit_tmp = exit_iohandle; |
+ const uint64_t out_key = reinterpret_cast<uint64_t>(out_tmp); |
+ const uint64_t err_key = reinterpret_cast<uint64_t>(err_tmp); |
+ const uint64_t exit_key = reinterpret_cast<uint64_t>(exit_tmp); |
+ const uint32_t events = EPOLLRDHUP | EPOLLIN; |
+ if (!out_tmp->AsyncWait(port, events, out_key)) { |
+ return false; |
+ } |
+ if (!err_tmp->AsyncWait(port, events, err_key)) { |
+ return false; |
+ } |
+ if (!exit_tmp->AsyncWait(port, events, exit_key)) { |
+ return false; |
+ } |
+ while ((out_tmp != NULL) || (err_tmp != NULL) || (exit_tmp != NULL)) { |
+ mx_port_packet_t pkt; |
+ status = |
+ mx_port_wait(port, MX_TIME_INFINITE, reinterpret_cast<void*>(&pkt), 0); |
+ if (status != MX_OK) { |
+ Log::PrintErr("Process::Wait: mx_port_wait failed: %s\n", |
+ mx_status_get_string(status)); |
+ return false; |
+ } |
+ IOHandle* event_handle = reinterpret_cast<IOHandle*>(pkt.key); |
+ const intptr_t event_mask = event_handle->WaitEnd(pkt.signal.observed); |
+ if (event_handle == out_tmp) { |
+ if ((event_mask & EPOLLIN) != 0) { |
+ const intptr_t avail = FDUtils::AvailableBytes(out_tmp->fd()); |
+ if (!out_data.Read(out_tmp->fd(), avail)) { |
+ return false; |
+ } |
+ } |
+ if ((event_mask & EPOLLRDHUP) != 0) { |
+ out_tmp->CancelWait(port, out_key); |
+ out_tmp = NULL; |
+ } |
+ } else if (event_handle == err_tmp) { |
+ if ((event_mask & EPOLLIN) != 0) { |
+ const intptr_t avail = FDUtils::AvailableBytes(err_tmp->fd()); |
+ if (!err_data.Read(err_tmp->fd(), avail)) { |
+ return false; |
+ } |
} |
+ if ((event_mask & EPOLLRDHUP) != 0) { |
+ err_tmp->CancelWait(port, err_key); |
+ err_tmp = NULL; |
+ } |
+ } else if (event_handle == exit_tmp) { |
+ if ((event_mask & EPOLLIN) != 0) { |
+ const intptr_t avail = FDUtils::AvailableBytes(exit_tmp->fd()); |
+ if (avail == 8) { |
+ intptr_t b = |
+ NO_RETRY_EXPECTED(read(exit_tmp->fd(), exit_code_data.bytes, 8)); |
+ if (b != 8) { |
+ return false; |
+ } |
+ } |
+ } |
+ if ((event_mask & EPOLLRDHUP) != 0) { |
+ exit_tmp->CancelWait(port, exit_key); |
+ exit_tmp = NULL; |
+ } |
+ } else { |
+ Log::PrintErr("Process::Wait: Unexpected wait key: %p\n", event_handle); |
} |
- if ((events[1] & EPOLLIN) != 0) { |
- const intptr_t avail = FDUtils::AvailableBytes(err); |
- if (!err_data.Read(err, avail)) { |
- return ProcessWaitCleanup(out, err, exit_event); |
+ if (out_tmp != NULL) { |
+ if (!out_tmp->AsyncWait(port, events, out_key)) { |
+ return false; |
} |
} |
- if ((events[2] & EPOLLIN) != 0) { |
- const intptr_t avail = FDUtils::AvailableBytes(exit_event); |
- if (avail == 8) { |
- intptr_t b = |
- NO_RETRY_EXPECTED(read(exit_event, exit_code_data.bytes, 8)); |
- if (b != 8) { |
- return ProcessWaitCleanup(out, err, exit_event); |
- } |
+ if (err_tmp != NULL) { |
+ if (!err_tmp->AsyncWait(port, events, err_key)) { |
+ return false; |
} |
} |
- for (size_t i = 0; i < kWaitItemsCount; ++i) { |
- if ((events[i] & EPOLLRDHUP) != 0) { |
- active--; |
- entries[i].Cancel(); |
+ if (exit_tmp != NULL) { |
+ if (!exit_tmp->AsyncWait(port, events, exit_key)) { |
+ return false; |
} |
} |
} |
@@ -731,18 +750,22 @@ class ProcessStarter { |
ExitCodeHandler::Start(); |
ExitCodeHandler::Add(process); |
+ // The IOHandles allocated below are returned to Dart code. The Dart code |
+ // calls into the runtime again to allocate a C++ Socket object, which |
+ // becomes the native field of a Dart _NativeSocket object. The C++ Socket |
+ // object and the EventHandler manage the lifetime of these IOHandles. |
*id_ = process; |
FDUtils::SetNonBlocking(read_in_); |
- *in_ = read_in_; |
+ *in_ = reinterpret_cast<intptr_t>(new IOHandle(read_in_)); |
read_in_ = -1; |
FDUtils::SetNonBlocking(read_err_); |
- *err_ = read_err_; |
+ *err_ = reinterpret_cast<intptr_t>(new IOHandle(read_err_)); |
read_err_ = -1; |
FDUtils::SetNonBlocking(write_out_); |
- *out_ = write_out_; |
+ *out_ = reinterpret_cast<intptr_t>(new IOHandle(write_out_)); |
write_out_ = -1; |
FDUtils::SetNonBlocking(exit_pipe_fds[0]); |
- *exit_event_ = exit_pipe_fds[0]; |
+ *exit_event_ = reinterpret_cast<intptr_t>(new IOHandle(exit_pipe_fds[0])); |
return 0; |
} |