| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <lib/fdio/fd.h> |
| #include <lib/fdio/fdio.h> |
| #include <lib/zxio/null.h> |
| #include <lib/zxio/ops.h> |
| #include <zircon/syscalls.h> |
| |
| typedef struct fdio_waitable { |
| zxio_t io; |
| |
| // arbitrary handle |
| zx_handle_t handle; |
| |
| // signals that cause ZXIO_SIGNAL_READABLE |
| zx_signals_t readable; |
| |
| // signals that cause ZXIO_SIGNAL_WRITABLE |
| zx_signals_t writable; |
| |
| // if true, don't close handle on close() op |
| bool shared_handle; |
| } fdio_waitable_t; |
| |
| static_assert(sizeof(fdio_waitable_t) <= sizeof(zxio_storage_t), |
| "fdio_waitable_t must fit inside zxio_storage_t."); |
| |
| static zx_status_t fdio_waitable_destroy(zxio_t* io) { |
| fdio_waitable_t* waitable = reinterpret_cast<fdio_waitable_t*>(io); |
| if (!waitable->shared_handle) { |
| zx_handle_t handle = waitable->handle; |
| waitable->handle = ZX_HANDLE_INVALID; |
| zx_handle_close(handle); |
| } |
| return ZX_OK; |
| } |
| |
| static zx_status_t fdio_waitable_close(zxio_t* io) { |
| // TODO(fxb/45407): When the syscall to detach a handle from its object is added, |
| // we should use that to mark the handle as detached, instead of closing |
| // the handle with risks of race behavior. |
| return ZX_OK; |
| } |
| |
| static void fdio_waitable_wait_begin(zxio_t* io, zxio_signals_t zxio_signals, |
| zx_handle_t* out_handle, zx_signals_t* out_zx_signals) { |
| fdio_waitable_t* waitable = reinterpret_cast<fdio_waitable_t*>(io); |
| zx_signals_t zx_signals = ZX_SIGNAL_NONE; |
| if (zxio_signals & ZXIO_SIGNAL_READABLE) { |
| zx_signals |= waitable->readable; |
| } |
| if (zxio_signals & ZXIO_SIGNAL_WRITABLE) { |
| zx_signals |= waitable->writable; |
| } |
| *out_handle = waitable->handle; |
| *out_zx_signals = zx_signals; |
| } |
| |
| static void fdio_waitable_wait_end(zxio_t* io, zx_signals_t zx_signals, |
| zxio_signals_t* out_zxio_signals) { |
| fdio_waitable_t* waitable = reinterpret_cast<fdio_waitable_t*>(io); |
| zxio_signals_t zxio_signals = ZXIO_SIGNAL_NONE; |
| if (zx_signals & waitable->readable) { |
| zxio_signals |= ZXIO_SIGNAL_READABLE; |
| } |
| if (zx_signals & waitable->writable) { |
| zxio_signals |= ZXIO_SIGNAL_WRITABLE; |
| } |
| *out_zxio_signals = zxio_signals; |
| } |
| |
| static constexpr zxio_ops_t fdio_waitable_ops = []() { |
| zxio_ops_t ops = zxio_default_ops; |
| ops.destroy = fdio_waitable_destroy; |
| ops.close = fdio_waitable_close; |
| ops.wait_begin = fdio_waitable_wait_begin; |
| ops.wait_end = fdio_waitable_wait_end; |
| return ops; |
| }(); |
| |
| static void fdio_waitable_init(zxio_storage_t* storage, zx_handle_t handle, zx_signals_t readable, |
| zx_signals_t writable, bool shared_handle) { |
| fdio_waitable_t* waitable = reinterpret_cast<fdio_waitable_t*>(storage); |
| zxio_init(&waitable->io, &fdio_waitable_ops); |
| waitable->handle = handle; |
| waitable->readable = readable; |
| waitable->writable = writable; |
| waitable->shared_handle = shared_handle; |
| } |
| |
| fdio_t* fdio_waitable_create(zx_handle_t handle, zx_signals_t readable, zx_signals_t writable, |
| bool shared_handle) { |
| zxio_storage_t* storage = nullptr; |
| fdio_t* io = fdio_zxio_create(&storage); |
| if (io == nullptr) { |
| if (!shared_handle) { |
| zx_handle_close(handle); |
| } |
| return nullptr; |
| } |
| fdio_waitable_init(storage, handle, readable, writable, shared_handle); |
| return io; |
| } |