diff --git a/zircon/system/core/devmgr/devhost/BUILD.gn b/zircon/system/core/devmgr/devhost/BUILD.gn index d83b5cc5759cbfe19ea87ae8c153d91059630edf..cf3143a98a84c1ddcd01595be8cdbc677ed83137 100644 --- a/zircon/system/core/devmgr/devhost/BUILD.gn +++ b/zircon/system/core/devmgr/devhost/BUILD.gn @@ -11,24 +11,23 @@ executable("devhost") { ] } -# "$zx/system/ulib/driver" is an alias for this. -library("driver") { - sdk = "shared" - sdk_headers = [] - shared = true - static = false +source_set("common") { + visibility = [ ":*" ] + sources = [ "api.cpp", "composite-device.cpp", + "connection-destroyer.cpp", "core.cpp", "devhost.cpp", + "proxy-iostate.cpp", "rpc-server.cpp", "scheduler_profile.cpp", "tracing.cpp", "zx-device.cpp", ] - configs += [ "$zx/public/gn/config:visibility_hidden" ] - deps = [ + + public_deps = [ "$zx/system/banjo/ddk.protocol.composite", "$zx/system/fidl/fuchsia-device:c", "$zx/system/fidl/fuchsia-device-manager:c", @@ -53,6 +52,21 @@ library("driver") { "../shared:env", ] configs += [ "$zx/public/gn/config:static-libc++" ] +} + +# "$zx/system/ulib/driver" is an alias for this. +library("driver") { + sdk = "shared" + sdk_headers = [] + shared = true + static = false + configs += [ "$zx/public/gn/config:visibility_hidden" ] + + sources = [] + + deps = [ + ":common", + ] # Since the tracing support is brought in via an archive, we need explicit # references to ensure everything is present. @@ -60,3 +74,15 @@ library("driver") { assert_no_deps = [ "$zx/system/ulib/trace-engine:trace-engine.shared" ] } + +test("devhost-test") { + test_group = "ddk" + sources = [ + "proxy-iostate-test.cpp", + ] + deps = [ + ":common", + "$zx/system/ulib/zxtest", + "../shared:env", + ] +} diff --git a/zircon/system/core/devmgr/devhost/connection-destroyer.cpp b/zircon/system/core/devmgr/devhost/connection-destroyer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a834ce570aebf45c39f79934d1ddf76f1174b697 --- /dev/null +++ b/zircon/system/core/devmgr/devhost/connection-destroyer.cpp @@ -0,0 +1,54 @@ +// Copyright 2019 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 "connection-destroyer.h" + +#include <inttypes.h> +#include "../shared/log.h" +#include "devhost.h" +#include "proxy-iostate.h" + +namespace devmgr { + +zx_status_t ConnectionDestroyer::QueueProxyConnection(async_dispatcher_t* dispatcher, + ProxyIostate* conn) { + zx_packet_user_t pkt = {}; + pkt.u64[0] = static_cast<uint64_t>(Type::Proxy); + pkt.u64[1] = reinterpret_cast<uintptr_t>(conn); + return receiver_.QueuePacket(dispatcher, &pkt); +} + +zx_status_t ConnectionDestroyer::QueueDeviceControllerConnection( + async_dispatcher_t* dispatcher, DeviceControllerConnection* conn) { + zx_packet_user_t pkt = {}; + pkt.u64[0] = static_cast<uint64_t>(Type::DeviceController); + pkt.u64[1] = reinterpret_cast<uintptr_t>(conn); + return receiver_.QueuePacket(dispatcher, &pkt); +} + +void ConnectionDestroyer::Handler(async_dispatcher_t* dispatcher, async::Receiver* receiver, + zx_status_t status, const zx_packet_user_t* data) { + Type type = static_cast<Type>(data->u64[0]); + uintptr_t ptr = data->u64[1]; + + switch (type) { + case Type::DeviceController: { + auto conn = reinterpret_cast<DeviceControllerConnection*>(ptr); + log(TRACE, "devhost: destroying devcoord conn '%p'\n", conn); + delete conn; + break; + } + case Type::Proxy: { + auto conn = reinterpret_cast<ProxyIostate*>(ptr); + log(TRACE, "devhost: destroying proxy conn '%p'\n", conn); + delete conn; + break; + } + default: + ZX_ASSERT_MSG(false, "Unknown IosDestructionType %" PRIu64 "\n", data->u64[0]); + } +} + +} // namespace devmgr + diff --git a/zircon/system/core/devmgr/devhost/connection-destroyer.h b/zircon/system/core/devmgr/devhost/connection-destroyer.h new file mode 100644 index 0000000000000000000000000000000000000000..89b3fa723e89fe1c6cad7337fa0c7cf7b4fec785 --- /dev/null +++ b/zircon/system/core/devmgr/devhost/connection-destroyer.h @@ -0,0 +1,50 @@ +// Copyright 2019 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. + +#pragma once + +#include <lib/async/cpp/receiver.h> +#include <zircon/syscalls.h> + +namespace devmgr { + +struct DeviceControllerConnection; +struct ProxyIostate; + +// Handles destroying Connection objects in the single-threaded DevhostAsyncLoop(). +// This allows us to prevent races between canceling waiting on the connection +// channel and executing the connection's handler. +class ConnectionDestroyer { +public: + static ConnectionDestroyer* Get() { + static ConnectionDestroyer destroyer; + return &destroyer; + } + + zx_status_t QueueDeviceControllerConnection(async_dispatcher_t* dispatcher, + DeviceControllerConnection* conn); + zx_status_t QueueProxyConnection(async_dispatcher_t* dispatcher, + ProxyIostate* conn); + +private: + ConnectionDestroyer() = default; + + ConnectionDestroyer(const ConnectionDestroyer&) = delete; + ConnectionDestroyer& operator=(const ConnectionDestroyer&) = delete; + + ConnectionDestroyer(ConnectionDestroyer&&) = delete; + ConnectionDestroyer& operator=(ConnectionDestroyer&&) = delete; + + static void Handler(async_dispatcher_t* dispatcher, async::Receiver* receiver, + zx_status_t status, const zx_packet_user_t* data); + + enum class Type { + DeviceController, + Proxy, + }; + + async::Receiver receiver_{ConnectionDestroyer::Handler}; +}; + +} // namespace devmgr diff --git a/zircon/system/core/devmgr/devhost/core.cpp b/zircon/system/core/devmgr/devhost/core.cpp index e29908a5486f0e82185e0c857d465b801c7bdaf3..2cd57ab373cb2ec2872ffbe8f2682cd89c7378a6 100644 --- a/zircon/system/core/devmgr/devhost/core.cpp +++ b/zircon/system/core/devmgr/devhost/core.cpp @@ -162,7 +162,20 @@ static zx_protocol_device_t device_invalid_ops = []() { #define DEAD_DEVICE_MAX 7 void devhost_device_destroy(zx_device_t* dev) REQ_DM_LOCK { - static fbl::DoublyLinkedList<zx_device*, zx_device::Node> dead_list; + // Wrap the deferred-deletion list in a struct, so we can give it a proper + // dtor. Otherwise, this causes the binary to crash on exit due to an + // is_empty assert in fbl::DoublyLinkedList. This was particularly a + // problem for unit tests. + struct DeadList { + ~DeadList() { + while (!devices.is_empty()) { + delete devices.pop_front(); + } + } + fbl::DoublyLinkedList<zx_device*, zx_device::Node> devices; + }; + + static DeadList dead_list; static unsigned dead_count = 0; // ensure any ops will be fatal @@ -187,10 +200,10 @@ void devhost_device_destroy(zx_device_t* dev) REQ_DM_LOCK { // Defer destruction to help catch use-after-free and also // so the compiler can't (easily) optimize away the poisoning // we do above. - dead_list.push_back(dev); + dead_list.devices.push_back(dev); if (dead_count == DEAD_DEVICE_MAX) { - zx_device_t* to_delete = dead_list.pop_front(); + zx_device_t* to_delete = dead_list.devices.pop_front(); delete to_delete; } else { dead_count++; diff --git a/zircon/system/core/devmgr/devhost/devhost.cpp b/zircon/system/core/devmgr/devhost/devhost.cpp index 97b14bb99e0648ba7de0244de7ceb59fad9d4f8a..bb0fb46d96a7fe9fb8af8fcee6d073192c3b0b07 100644 --- a/zircon/system/core/devmgr/devhost/devhost.cpp +++ b/zircon/system/core/devmgr/devhost/devhost.cpp @@ -46,7 +46,9 @@ #include "../shared/fidl_txn.h" #include "../shared/log.h" #include "composite-device.h" +#include "connection-destroyer.h" #include "main.h" +#include "proxy-iostate.h" #include "scheduler_profile.h" #include "tracing.h" @@ -59,26 +61,6 @@ namespace devmgr { uint32_t log_flags = LOG_ERROR | LOG_INFO; -struct ProxyIostate : AsyncLoopOwnedRpcHandler<ProxyIostate> { - ProxyIostate() = default; - ~ProxyIostate(); - - // Creates a ProxyIostate and points |dev| at it. The ProxyIostate is owned - // by the async loop, and its destruction may be requested by calling - // Cancel(). - static zx_status_t Create(const fbl::RefPtr<zx_device_t>& dev, zx::channel rpc); - - // Request the destruction of the proxy connection - void Cancel(); - - static void HandleRpc(fbl::unique_ptr<ProxyIostate> conn, async_dispatcher_t* dispatcher, - async::WaitBase* wait, zx_status_t status, - const zx_packet_signal_t* signal); - - fbl::RefPtr<zx_device_t> dev; -}; -static void proxy_ios_destroy(const fbl::RefPtr<zx_device_t>& dev); - static fbl::DoublyLinkedList<fbl::RefPtr<zx_driver>> dh_drivers; // Access the devhost's async event loop @@ -98,77 +80,6 @@ static zx_status_t SetupRootDevcoordinatorConnection(zx::channel ch) { DevhostAsyncLoop()->dispatcher()); } -// Handles destroying Connection objects in the single-threaded DevhostAsyncLoop(). -// This allows us to prevent races between canceling waiting on the connection -// channel and executing the connection's handler. -class ConnectionDestroyer { -public: - static ConnectionDestroyer* Get() { - static ConnectionDestroyer destroyer; - return &destroyer; - } - - zx_status_t QueueDeviceControllerConnection(DeviceControllerConnection* conn); - zx_status_t QueueProxyConnection(ProxyIostate* conn); - -private: - ConnectionDestroyer() = default; - - ConnectionDestroyer(const ConnectionDestroyer&) = delete; - ConnectionDestroyer& operator=(const ConnectionDestroyer&) = delete; - - ConnectionDestroyer(ConnectionDestroyer&&) = delete; - ConnectionDestroyer& operator=(ConnectionDestroyer&&) = delete; - - static void Handler(async_dispatcher_t* dispatcher, async::Receiver* receiver, - zx_status_t status, const zx_packet_user_t* data); - - enum class Type { - DeviceController, - Proxy, - }; - - async::Receiver receiver_{ConnectionDestroyer::Handler}; -}; - -zx_status_t ConnectionDestroyer::QueueProxyConnection(ProxyIostate* conn) { - zx_packet_user_t pkt = {}; - pkt.u64[0] = static_cast<uint64_t>(Type::Proxy); - pkt.u64[1] = reinterpret_cast<uintptr_t>(conn); - return receiver_.QueuePacket(DevhostAsyncLoop()->dispatcher(), &pkt); -} - -zx_status_t ConnectionDestroyer::QueueDeviceControllerConnection( - DeviceControllerConnection* conn) { - zx_packet_user_t pkt = {}; - pkt.u64[0] = static_cast<uint64_t>(Type::DeviceController); - pkt.u64[1] = reinterpret_cast<uintptr_t>(conn); - return receiver_.QueuePacket(DevhostAsyncLoop()->dispatcher(), &pkt); -} - -void ConnectionDestroyer::Handler(async_dispatcher_t* dispatcher, async::Receiver* receiver, - zx_status_t status, const zx_packet_user_t* data) { - Type type = static_cast<Type>(data->u64[0]); - uintptr_t ptr = data->u64[1]; - - switch (type) { - case Type::DeviceController: { - auto conn = reinterpret_cast<DeviceControllerConnection*>(ptr); - log(TRACE, "devhost: destroying devcoord conn '%p'\n", conn); - delete conn; - break; - } - case Type::Proxy: { - auto conn = reinterpret_cast<ProxyIostate*>(ptr); - log(TRACE, "devhost: destroying proxy conn '%p'\n", conn); - delete conn; - break; - } - default: - ZX_ASSERT_MSG(false, "Unknown IosDestructionType %" PRIu64 "\n", data->u64[0]); - } -} - static const char* mkdevpath(const fbl::RefPtr<zx_device_t>& dev, char* path, size_t max) { if (dev == nullptr) { return ""; @@ -607,7 +518,7 @@ static zx_status_t fidl_ConnectProxy(void* raw_ctx, zx_handle_t raw_shadow) { ctx->conn->dev->ops->rxrpc(ctx->conn->dev->ctx, ZX_HANDLE_INVALID); // Ignore any errors in the creation for now? // TODO(teisenbe/kulakowski): Investigate if this is the right thing - ProxyIostate::Create(ctx->conn->dev, std::move(shadow)); + ProxyIostate::Create(ctx->conn->dev, std::move(shadow), DevhostAsyncLoop()->dispatcher()); return ZX_OK; } @@ -824,91 +735,11 @@ void DevfsConnection::HandleRpc(fbl::unique_ptr<DevfsConnection> conn, log(TRACE, "devhost: destroying devfs conn %p\n", conn.get()); } -ProxyIostate::~ProxyIostate() { - fbl::AutoLock guard(&dev->proxy_ios_lock); - if (dev->proxy_ios == this) { - dev->proxy_ios = nullptr; - } -} - -// Handling RPC From Proxy Devices to BusDevs -void ProxyIostate::HandleRpc(fbl::unique_ptr<ProxyIostate> conn, async_dispatcher_t* dispatcher, - async::WaitBase* wait, zx_status_t status, - const zx_packet_signal_t* signal) { - if (status != ZX_OK) { - return; - } - - if (conn->dev == nullptr) { - log(RPC_SDW, "proxy-rpc: stale rpc? (ios=%p)\n", conn.get()); - // Do not re-issue the wait here - return; - } - if (signal->observed & ZX_CHANNEL_READABLE) { - log(RPC_SDW, "proxy-rpc: rpc readable (ios=%p,dev=%p)\n", conn.get(), conn->dev.get()); - zx_status_t r = conn->dev->ops->rxrpc(conn->dev->ctx, wait->object()); - if (r != ZX_OK) { - log(RPC_SDW, "proxy-rpc: rpc cb error %d (ios=%p,dev=%p)\n", r, conn.get(), - conn->dev.get()); - // Let |conn| be destroyed - return; - } - BeginWait(std::move(conn), dispatcher); - return; - } - if (signal->observed & ZX_CHANNEL_PEER_CLOSED) { - log(RPC_SDW, "proxy-rpc: peer closed (ios=%p,dev=%p)\n", conn.get(), conn->dev.get()); - // Let |conn| be destroyed - return; - } - log(ERROR, "devhost: no work? %08x\n", signal->observed); - BeginWait(std::move(conn), dispatcher); -} - -zx_status_t ProxyIostate::Create(const fbl::RefPtr<zx_device_t>& dev, zx::channel rpc) { - // This must be held for the adding of the channel to the port, since the - // async loop may run immediately after that point. - fbl::AutoLock guard(&dev->proxy_ios_lock); - - if (dev->proxy_ios) { - dev->proxy_ios->Cancel(); - dev->proxy_ios = nullptr; - } - - auto ios = std::make_unique<ProxyIostate>(); - if (ios == nullptr) { - return ZX_ERR_NO_MEMORY; - } - - ios->dev = dev; - ios->set_channel(std::move(rpc)); - - // |ios| is will be owned by the async loop. |dev| holds a reference that will be - // cleared prior to destruction. - dev->proxy_ios = ios.get(); - - zx_status_t status = BeginWait(std::move(ios), DevhostAsyncLoop()->dispatcher()); - if (status != ZX_OK) { - dev->proxy_ios = nullptr; - return status; - } - - return ZX_OK; -} - -// The device for which ProxyIostate is currently attached to should have -// its proxy_ios_lock held across Cancel(). -void ProxyIostate::Cancel() { - // TODO(teisenbe): We should probably check the return code in case the - // queue was full - ConnectionDestroyer::Get()->QueueProxyConnection(this); -} - static void proxy_ios_destroy(const fbl::RefPtr<zx_device_t>& dev) { fbl::AutoLock guard(&dev->proxy_ios_lock); if (dev->proxy_ios) { - dev->proxy_ios->Cancel(); + dev->proxy_ios->Cancel(DevhostAsyncLoop()->dispatcher()); } dev->proxy_ios = nullptr; } @@ -1144,7 +975,8 @@ zx_status_t devhost_remove(const fbl::RefPtr<zx_device_t>& dev) { dev->rpc = zx::unowned_channel(); // queue an event to destroy the connection - ConnectionDestroyer::Get()->QueueDeviceControllerConnection(conn); + ConnectionDestroyer::Get()->QueueDeviceControllerConnection(DevhostAsyncLoop()->dispatcher(), + conn); // shut down our proxy rpc channel if it exists proxy_ios_destroy(dev); diff --git a/zircon/system/core/devmgr/devhost/devhost.h b/zircon/system/core/devmgr/devhost/devhost.h index 74f1521686564a128ad96b5116438b3a786f9770..da85a0a84be66c415c54b0973ce961d7e942ff29 100644 --- a/zircon/system/core/devmgr/devhost/devhost.h +++ b/zircon/system/core/devmgr/devhost/devhost.h @@ -18,6 +18,7 @@ #include <fbl/string.h> #include <fbl/unique_ptr.h> #include <lib/async/cpp/wait.h> +#include <lib/async-loop/cpp/loop.h> #include <lib/zx/channel.h> #include <zircon/compiler.h> #include <zircon/fidl.h> diff --git a/zircon/system/core/devmgr/devhost/proxy-iostate-test.cpp b/zircon/system/core/devmgr/devhost/proxy-iostate-test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..752ab43f5ad802364feb198cf1ac686e00eef924 --- /dev/null +++ b/zircon/system/core/devmgr/devhost/proxy-iostate-test.cpp @@ -0,0 +1,28 @@ +// Copyright 2019 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/async-loop/cpp/loop.h> +#include <zxtest/zxtest.h> +#include "proxy-iostate.h" +#include "zx-device.h" + +TEST(ProxyIostateTestCase, Creation) { + async::Loop loop(&kAsyncLoopConfigNoAttachToThread); + + fbl::RefPtr<zx_device> dev; + ASSERT_OK(zx_device::Create(&dev)); + + zx::channel proxy_local, proxy_remote; + ASSERT_OK(zx::channel::create(0, &proxy_local, &proxy_remote)); + + ASSERT_OK(devmgr::ProxyIostate::Create(dev, std::move(proxy_remote), loop.dispatcher())); + + ASSERT_OK(loop.RunUntilIdle()); +} + + +int main(int argc, char** argv) { + return RUN_ALL_TESTS(argc, argv); +} + diff --git a/zircon/system/core/devmgr/devhost/proxy-iostate.cpp b/zircon/system/core/devmgr/devhost/proxy-iostate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..689c4b00ab2bb6c1c93009694aecc981d70da659 --- /dev/null +++ b/zircon/system/core/devmgr/devhost/proxy-iostate.cpp @@ -0,0 +1,95 @@ +// Copyright 2019 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 "proxy-iostate.h" + +#include <fbl/auto_lock.h> +#include "../shared/log.h" +#include "connection-destroyer.h" +#include "zx-device.h" + +namespace devmgr { + +ProxyIostate::~ProxyIostate() { + fbl::AutoLock guard(&dev->proxy_ios_lock); + if (dev->proxy_ios == this) { + dev->proxy_ios = nullptr; + } +} + +// Handling RPC From Proxy Devices to BusDevs +void ProxyIostate::HandleRpc(fbl::unique_ptr<ProxyIostate> conn, async_dispatcher_t* dispatcher, + async::WaitBase* wait, zx_status_t status, + const zx_packet_signal_t* signal) { + if (status != ZX_OK) { + return; + } + + if (conn->dev == nullptr) { + log(RPC_SDW, "proxy-rpc: stale rpc? (ios=%p)\n", conn.get()); + // Do not re-issue the wait here + return; + } + if (signal->observed & ZX_CHANNEL_READABLE) { + log(RPC_SDW, "proxy-rpc: rpc readable (ios=%p,dev=%p)\n", conn.get(), conn->dev.get()); + zx_status_t r = conn->dev->ops->rxrpc(conn->dev->ctx, wait->object()); + if (r != ZX_OK) { + log(RPC_SDW, "proxy-rpc: rpc cb error %d (ios=%p,dev=%p)\n", r, conn.get(), + conn->dev.get()); + // Let |conn| be destroyed + return; + } + BeginWait(std::move(conn), dispatcher); + return; + } + if (signal->observed & ZX_CHANNEL_PEER_CLOSED) { + log(RPC_SDW, "proxy-rpc: peer closed (ios=%p,dev=%p)\n", conn.get(), conn->dev.get()); + // Let |conn| be destroyed + return; + } + log(ERROR, "devhost: no work? %08x\n", signal->observed); + BeginWait(std::move(conn), dispatcher); +} + +zx_status_t ProxyIostate::Create(const fbl::RefPtr<zx_device_t>& dev, zx::channel rpc, + async_dispatcher_t* dispatcher) { + // This must be held for the adding of the channel to the port, since the + // async loop may run immediately after that point. + fbl::AutoLock guard(&dev->proxy_ios_lock); + + if (dev->proxy_ios) { + dev->proxy_ios->Cancel(dispatcher); + dev->proxy_ios = nullptr; + } + + auto ios = std::make_unique<ProxyIostate>(); + if (ios == nullptr) { + return ZX_ERR_NO_MEMORY; + } + + ios->dev = dev; + ios->set_channel(std::move(rpc)); + + // |ios| is will be owned by the async loop. |dev| holds a reference that will be + // cleared prior to destruction. + dev->proxy_ios = ios.get(); + + zx_status_t status = BeginWait(std::move(ios), dispatcher); + if (status != ZX_OK) { + dev->proxy_ios = nullptr; + return status; + } + + return ZX_OK; +} + +// The device for which ProxyIostate is currently attached to should have +// its proxy_ios_lock held across Cancel(). +void ProxyIostate::Cancel(async_dispatcher_t* dispatcher) { + // TODO(teisenbe): We should probably check the return code in case the + // queue was full + ConnectionDestroyer::Get()->QueueProxyConnection(dispatcher, this); +} + +} // namespace devmgr diff --git a/zircon/system/core/devmgr/devhost/proxy-iostate.h b/zircon/system/core/devmgr/devhost/proxy-iostate.h new file mode 100644 index 0000000000000000000000000000000000000000..83615b576c36ddbbc72fd52b666ab82aaadaae71 --- /dev/null +++ b/zircon/system/core/devmgr/devhost/proxy-iostate.h @@ -0,0 +1,38 @@ +// Copyright 2019 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. + +#pragma once + +#include <fbl/ref_ptr.h> +#include <fbl/unique_ptr.h> +#include <lib/async/cpp/wait.h> +#include <lib/zx/channel.h> +#include "../shared/async-loop-owned-rpc-handler.h" + +struct zx_device; + +namespace devmgr { + +struct ProxyIostate : AsyncLoopOwnedRpcHandler<ProxyIostate> { + ProxyIostate() = default; + ~ProxyIostate(); + + // Creates a ProxyIostate and points |dev| at it. The ProxyIostate is owned + // by the async loop, and its destruction may be requested by calling + // Cancel(). + static zx_status_t Create(const fbl::RefPtr<zx_device>& dev, zx::channel rpc, + async_dispatcher_t* dispatcher); + + // Request the destruction of the proxy connection + void Cancel(async_dispatcher_t* dispatcher); + + static void HandleRpc(fbl::unique_ptr<ProxyIostate> conn, async_dispatcher_t* dispatcher, + async::WaitBase* wait, zx_status_t status, + const zx_packet_signal_t* signal); + + fbl::RefPtr<zx_device> dev; +}; +static void proxy_ios_destroy(const fbl::RefPtr<zx_device>& dev); + +} // namespace devmgr diff --git a/zircon/system/utest/BUILD.gn b/zircon/system/utest/BUILD.gn index 8a8ede7aa314c200fd530b17e0f77adab1a66bdc..1eb2a0824e88ff81c700bc3611e319887ccf39cc 100644 --- a/zircon/system/utest/BUILD.gn +++ b/zircon/system/utest/BUILD.gn @@ -20,6 +20,7 @@ if (current_cpu != "") { ":host", # TODO(mcgrathr): reach this differently? "$zx/system/core/bootsvc:tests", "$zx/system/core/devmgr/devcoordinator:devcoordinator-test", + "$zx/system/core/devmgr/devhost:devhost-test", "$zx/system/core/devmgr/fshost:block-watcher-test", "$zx/system/core/devmgr/fshost:fshost-test", "$zx/system/core/virtcon:virtual-console-test",