[devmgr] Split Device into its own source files
In an effort to split coordinator.cpp into smaller, more understandable
pieces, split out Device into its own source files.
Test: Ran Fuchsia and /system/test/ddk tests.
Change-Id: Ie60d49435bff2877de30abb0c61f4e72f1a5ac1b
diff --git a/system/core/devmgr/devmgr/coordinator.cpp b/system/core/devmgr/devmgr/coordinator.cpp
index fe083f6..61f3b60 100644
--- a/system/core/devmgr/devmgr/coordinator.cpp
+++ b/system/core/devmgr/devmgr/coordinator.cpp
@@ -544,11 +544,6 @@
return ZX_OK;
}
-Devhost::Devhost()
- : hrpc_(ZX_HANDLE_INVALID), proc_(ZX_HANDLE_INVALID), koid_(0), refcount_(0),
- flags_(0), parent_(nullptr) {
-}
-
zx_status_t Coordinator::NewDevhost(const char* name, Devhost* parent, Devhost** out) {
auto dh = fbl::make_unique<Devhost>();
if (dh == nullptr) {
@@ -637,15 +632,6 @@
delete dev;
}
-Device::Device(Coordinator* coord)
- : coordinator(coord), publish_task([this] { coordinator->HandleNewDevice(this); }) {}
-
-Device::~Device() {
- // TODO: cancel any pending rpc responses. This clear is a hack to prevent
- // pending's dtor from asserting.
- pending.clear();
-}
-
// Add a new device to a parent device (same devhost)
// New device is published in devfs.
// Caller closes handles on error, so we don't have to.
@@ -831,7 +817,7 @@
// A side-effect of this is that the devhost will be released,
// as well as any proxy devices.
if (forced) {
- dh->flags() |= DEV_HOST_DYING;
+ dh->flags() |= Devhost::Flags::kDying;
Device* next;
Device* last = nullptr;
@@ -876,7 +862,8 @@
// THEN we will want to rebind our parent
if (!(parent->flags & DEV_CTX_DEAD) &&
(parent->flags & DEV_CTX_MUST_ISOLATE) &&
- ((parent->host == nullptr) || !(parent->host->flags() & DEV_HOST_DYING))) {
+ ((parent->host == nullptr) ||
+ !(parent->host->flags() & Devhost::Flags::kDying))) {
log(DEVLC, "devcoord: bus device %p name='%s' is unbound\n",
parent, parent->name);
@@ -1458,39 +1445,6 @@
return ZX_OK;
}
-// handle inbound messages from devhost to devices
-void Device::HandleRpc(Device* dev, async_dispatcher_t* dispatcher,
- async::WaitBase* wait, zx_status_t status,
- const zx_packet_signal_t* signal) {
- if (status != ZX_OK) {
- log(ERROR, "devcoord: Device::HandleRpc aborting, saw status %d\n", status);
- return;
- }
-
- if (signal->observed & ZX_CHANNEL_READABLE) {
- zx_status_t r;
- if ((r = dev->coordinator->HandleDeviceRead(dev)) < 0) {
- if (r != ZX_ERR_STOP) {
- log(ERROR, "devcoord: device %p name='%s' rpc status: %d\n",
- dev, dev->name, r);
- }
- dev->coordinator->RemoveDevice(dev, true);
- // Do not start waiting again on this device's channel again
- return;
- }
- Device::BeginWait(dev, dispatcher);
- return;
- }
- if (signal->observed & ZX_CHANNEL_PEER_CLOSED) {
- log(ERROR, "devcoord: device %p name='%s' disconnected!\n", dev, dev->name);
- dev->coordinator->RemoveDevice(dev, true);
- // Do not start waiting again on this device's channel again
- return;
- }
- log(ERROR, "devcoord: no work? %08x\n", signal->observed);
- Device::BeginWait(dev, dispatcher);
-}
-
// send message to devhost, requesting the creation of a device
static zx_status_t dh_create_device(Device* dev, Devhost* dh,
const char* args, zx::handle rpc_proxy) {
@@ -1767,7 +1721,7 @@
return r;
}
- dh->flags() |= DEV_HOST_SUSPEND;
+ dh->flags() |= Devhost::Flags::kSuspend;
auto pending = fbl::make_unique<PendingOperation>(PendingOperation::Op::kSuspend, ctx);
if (pending == nullptr) {
diff --git a/system/core/devmgr/devmgr/coordinator.h b/system/core/devmgr/devmgr/coordinator.h
index 2fa6e8a..15327b9 100644
--- a/system/core/devmgr/devmgr/coordinator.h
+++ b/system/core/devmgr/devmgr/coordinator.h
@@ -11,9 +11,7 @@
#include <fbl/string.h>
#include <fbl/unique_ptr.h>
#include <fbl/vector.h>
-#include <lib/async/cpp/task.h>
#include <lib/async/cpp/wait.h>
-#include <lib/async-loop/cpp/loop.h>
#include <lib/fit/function.h>
#include <lib/zx/channel.h>
#include <lib/zx/job.h>
@@ -23,160 +21,20 @@
#include <utility>
+#include "device.h"
#include "metadata.h"
namespace devmgr {
-class Coordinator;
-class Devhost;
class DevhostLoaderService;
-struct Devnode;
-class SuspendContext;
-
-class PendingOperation {
-public:
- enum struct Op : uint32_t {
- kBind = 1,
- kSuspend = 2,
- };
-
- PendingOperation(Op op, SuspendContext* context) : op_(op), context_(context) {}
-
- struct Node {
- static fbl::DoublyLinkedListNodeState<fbl::unique_ptr<PendingOperation>>& node_state(
- PendingOperation& obj) {
- return obj.node_;
- }
- };
-
- Op op() const { return op_; }
- SuspendContext* context() const { return context_; }
-
-private:
- fbl::DoublyLinkedListNodeState<fbl::unique_ptr<PendingOperation>> node_;
-
- Op op_;
- SuspendContext* context_;
-};
-
-#define DEV_HOST_DYING 1
-#define DEV_HOST_SUSPEND 2
-
-struct Device {
- explicit Device(Coordinator* coord);
- ~Device();
-
- // Begins waiting in |dispatcher| on |dev->wait|. This transfers a
- // reference of |dev| to the dispatcher. The dispatcher returns ownership
- // when the of that reference when the handler is invoked.
- // TODO(teisenbe/kulakowski): Make this take a RefPtr
- static zx_status_t BeginWait(Device* dev, async_dispatcher_t* dispatcher) {
- // TODO(teisenbe/kulakowski): Once this takes a refptr, we should leak a
- // ref in the success case (to present the ref owned by the dispatcher).
- return dev->wait.Begin(dispatcher);
- }
-
- // Entrypoint for the RPC handler that captures the pointer ownership
- // semantics.
- void HandleRpcEntry(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
- const zx_packet_signal_t* signal) {
- // TODO(teisenbe/kulakowski): Perform the appropriate dance to construct
- // a RefPtr from |this| without a net-increase in refcount, to represent
- // the dispatcher passing ownership of its reference to the handler
- HandleRpc(this, dispatcher, wait, status, signal);
- }
-
- // TODO(teisenbe/kulakowski): Make this take a RefPtr
- static void HandleRpc(Device* dev, async_dispatcher_t* dispatcher,
- async::WaitBase* wait, zx_status_t status,
- const zx_packet_signal_t* signal);
-
- Coordinator* coordinator;
- zx::channel hrpc;
- uint32_t flags = 0;
-
- async::WaitMethod<Device, &Device::HandleRpcEntry> wait{this};
- async::TaskClosure publish_task;
-
- Devhost* host = nullptr;
- const char* name = nullptr;
- const char* libname = nullptr;
- fbl::unique_ptr<const char[]> args;
- // The backoff between each driver retry. This grows exponentially.
- zx::duration backoff = zx::msec(250);
- // The number of retries left for the driver.
- uint32_t retries = 4;
- mutable int32_t refcount_ = 0;
- uint32_t protocol_id = 0;
- uint32_t prop_count = 0;
- Devnode* self = nullptr;
- Devnode* link = nullptr;
- Device* parent = nullptr;
- Device* proxy = nullptr;
-
- // For attaching as an open connection to the proxy device,
- // or once the device becomes visible.
- zx::channel client_remote;
-
- // listnode for this device in its parent's
- // list-of-children
- fbl::DoublyLinkedListNodeState<Device*> node;
- struct Node {
- static fbl::DoublyLinkedListNodeState<Device*>& node_state(
- Device& obj) {
- return obj.node;
- }
- };
-
- // listnode for this device in its devhost's
- // list-of-devices
- fbl::DoublyLinkedListNodeState<Device*> dhnode;
- struct DevhostNode {
- static fbl::DoublyLinkedListNodeState<Device*>& node_state(
- Device& obj) {
- return obj.dhnode;
- }
- };
-
- // list of all child devices of this device
- fbl::DoublyLinkedList<Device*, Node> children;
-
- // list of outstanding requests from the devcoord
- // to this device's devhost, awaiting a response
- fbl::DoublyLinkedList<fbl::unique_ptr<PendingOperation>, PendingOperation::Node> pending;
-
- // listnode for this device in the all devices list
- fbl::DoublyLinkedListNodeState<Device*> anode;
- struct AllDevicesNode {
- static fbl::DoublyLinkedListNodeState<Device*>& node_state(
- Device& obj) {
- return obj.anode;
- }
- };
-
- // Metadata entries associated to this device.
- fbl::DoublyLinkedList<fbl::unique_ptr<Metadata>, Metadata::Node> metadata;
-
- fbl::unique_ptr<zx_device_prop_t[]> props;
-
- // Allocation backing |name| and |libname|
- fbl::unique_ptr<char[]> name_alloc_;
-
- // The AddRef and Release functions follow the contract for fbl::RefPtr.
- void AddRef() const {
- ++refcount_;
- }
-
- // Returns true when the last reference has been released.
- bool Release() const {
- const int32_t rc = refcount_;
- --refcount_;
- return rc == 1;
- }
-};
class Devhost {
public:
+ enum Flags : uint32_t {
+ kDying = 1 << 0,
+ kSuspend = 1 << 1,
+ };
+
struct AllDevhostsNode {
static fbl::DoublyLinkedListNodeState<Devhost*>& node_state(
Devhost& obj) {
@@ -196,8 +54,6 @@
}
};
- Devhost();
-
zx_handle_t hrpc() const { return hrpc_; }
void set_hrpc(zx_handle_t hrpc) { hrpc_ = hrpc; }
zx::unowned_process proc() const { return zx::unowned_process(proc_); }
@@ -225,12 +81,12 @@
private:
async::Wait wait_;
- zx_handle_t hrpc_;
+ zx_handle_t hrpc_ = ZX_HANDLE_INVALID;
zx::process proc_;
- zx_koid_t koid_;
- mutable int32_t refcount_;
- uint32_t flags_;
- Devhost* parent_;
+ zx_koid_t koid_ = 0;
+ mutable int32_t refcount_ = 0;
+ uint32_t flags_ = 0;
+ Devhost* parent_ = nullptr;
// list of all devices on this devhost
fbl::DoublyLinkedList<Device*, Device::DevhostNode> devices_;
@@ -250,13 +106,12 @@
class SuspendContext {
public:
- enum struct Flags : uint32_t {
+ enum class Flags : uint32_t {
kRunning = 0u,
kSuspend = 1u,
};
- SuspendContext() {
- }
+ SuspendContext() = default;
SuspendContext(Coordinator* coordinator,
Flags flags, uint32_t sflags, zx::socket socket,
diff --git a/system/core/devmgr/devmgr/device.cpp b/system/core/devmgr/devmgr/device.cpp
new file mode 100644
index 0000000..23641da
--- /dev/null
+++ b/system/core/devmgr/devmgr/device.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 "device.h"
+
+#include "../shared/log.h"
+#include "coordinator.h"
+
+namespace devmgr {
+
+Device::Device(Coordinator* coord)
+ : coordinator(coord), publish_task([this] { coordinator->HandleNewDevice(this); }) {}
+
+Device::~Device() {
+ // TODO: cancel any pending rpc responses. This clear is a hack to prevent
+ // pending's dtor from asserting.
+ pending.clear();
+}
+
+// Handle inbound messages from devhost to devices
+void Device::HandleRpc(Device* dev, async_dispatcher_t* dispatcher,
+ async::WaitBase* wait, zx_status_t status,
+ const zx_packet_signal_t* signal) {
+ if (status != ZX_OK) {
+ log(ERROR, "devcoord: Device::HandleRpc aborting, saw status %d\n", status);
+ return;
+ }
+
+ if (signal->observed & ZX_CHANNEL_READABLE) {
+ zx_status_t r;
+ if ((r = dev->coordinator->HandleDeviceRead(dev)) < 0) {
+ if (r != ZX_ERR_STOP) {
+ log(ERROR, "devcoord: device %p name='%s' rpc status: %d\n",
+ dev, dev->name, r);
+ }
+ dev->coordinator->RemoveDevice(dev, true);
+ // Do not start waiting again on this device's channel again
+ return;
+ }
+ Device::BeginWait(dev, dispatcher);
+ return;
+ }
+ if (signal->observed & ZX_CHANNEL_PEER_CLOSED) {
+ log(ERROR, "devcoord: device %p name='%s' disconnected!\n", dev, dev->name);
+ dev->coordinator->RemoveDevice(dev, true);
+ // Do not start waiting again on this device's channel again
+ return;
+ }
+ log(ERROR, "devcoord: no work? %08x\n", signal->observed);
+ Device::BeginWait(dev, dispatcher);
+}
+
+} // namespace devmgr
diff --git a/system/core/devmgr/devmgr/device.h b/system/core/devmgr/devmgr/device.h
new file mode 100644
index 0000000..a39db45
--- /dev/null
+++ b/system/core/devmgr/devmgr/device.h
@@ -0,0 +1,160 @@
+// 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 <ddk/device.h>
+#include <lib/async/cpp/task.h>
+#include <lib/async/cpp/wait.h>
+#include <lib/zx/channel.h>
+
+#include "metadata.h"
+
+namespace devmgr {
+
+class Coordinator;
+class Devhost;
+struct Devnode;
+class SuspendContext;
+
+class PendingOperation {
+public:
+ enum class Op : uint32_t {
+ kBind = 1,
+ kSuspend = 2,
+ };
+
+ PendingOperation(Op op, SuspendContext* context) : op_(op), context_(context) {}
+
+ struct Node {
+ static fbl::DoublyLinkedListNodeState<fbl::unique_ptr<PendingOperation>>& node_state(
+ PendingOperation& obj) {
+ return obj.node_;
+ }
+ };
+
+ Op op() const { return op_; }
+ SuspendContext* context() const { return context_; }
+
+private:
+ fbl::DoublyLinkedListNodeState<fbl::unique_ptr<PendingOperation>> node_;
+
+ Op op_;
+ SuspendContext* context_;
+};
+
+struct Device {
+ explicit Device(Coordinator* coord);
+ ~Device();
+
+ // Begins waiting in |dispatcher| on |dev->wait|. This transfers a
+ // reference of |dev| to the dispatcher. The dispatcher returns ownership
+ // when the of that reference when the handler is invoked.
+ // TODO(teisenbe/kulakowski): Make this take a RefPtr
+ static zx_status_t BeginWait(Device* dev, async_dispatcher_t* dispatcher) {
+ // TODO(teisenbe/kulakowski): Once this takes a refptr, we should leak a
+ // ref in the success case (to present the ref owned by the dispatcher).
+ return dev->wait.Begin(dispatcher);
+ }
+
+ // Entrypoint for the RPC handler that captures the pointer ownership
+ // semantics.
+ void HandleRpcEntry(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
+ const zx_packet_signal_t* signal) {
+ // TODO(teisenbe/kulakowski): Perform the appropriate dance to construct
+ // a RefPtr from |this| without a net-increase in refcount, to represent
+ // the dispatcher passing ownership of its reference to the handler
+ HandleRpc(this, dispatcher, wait, status, signal);
+ }
+
+ // TODO(teisenbe/kulakowski): Make this take a RefPtr
+ static void HandleRpc(Device* dev, async_dispatcher_t* dispatcher,
+ async::WaitBase* wait, zx_status_t status,
+ const zx_packet_signal_t* signal);
+
+ Coordinator* coordinator;
+ zx::channel hrpc;
+ uint32_t flags = 0;
+
+ async::WaitMethod<Device, &Device::HandleRpcEntry> wait{this};
+ async::TaskClosure publish_task;
+
+ Devhost* host = nullptr;
+ const char* name = nullptr;
+ const char* libname = nullptr;
+ fbl::unique_ptr<const char[]> args;
+ // The backoff between each driver retry. This grows exponentially.
+ zx::duration backoff = zx::msec(250);
+ // The number of retries left for the driver.
+ uint32_t retries = 4;
+ mutable int32_t refcount_ = 0;
+ uint32_t protocol_id = 0;
+ uint32_t prop_count = 0;
+ Devnode* self = nullptr;
+ Devnode* link = nullptr;
+ Device* parent = nullptr;
+ Device* proxy = nullptr;
+
+ // For attaching as an open connection to the proxy device,
+ // or once the device becomes visible.
+ zx::channel client_remote;
+
+ // listnode for this device in its parent's
+ // list-of-children
+ fbl::DoublyLinkedListNodeState<Device*> node;
+ struct Node {
+ static fbl::DoublyLinkedListNodeState<Device*>& node_state(
+ Device& obj) {
+ return obj.node;
+ }
+ };
+
+ // listnode for this device in its devhost's
+ // list-of-devices
+ fbl::DoublyLinkedListNodeState<Device*> dhnode;
+ struct DevhostNode {
+ static fbl::DoublyLinkedListNodeState<Device*>& node_state(
+ Device& obj) {
+ return obj.dhnode;
+ }
+ };
+
+ // list of all child devices of this device
+ fbl::DoublyLinkedList<Device*, Node> children;
+
+ // list of outstanding requests from the devcoord
+ // to this device's devhost, awaiting a response
+ fbl::DoublyLinkedList<fbl::unique_ptr<PendingOperation>, PendingOperation::Node> pending;
+
+ // listnode for this device in the all devices list
+ fbl::DoublyLinkedListNodeState<Device*> anode;
+ struct AllDevicesNode {
+ static fbl::DoublyLinkedListNodeState<Device*>& node_state(
+ Device& obj) {
+ return obj.anode;
+ }
+ };
+
+ // Metadata entries associated to this device.
+ fbl::DoublyLinkedList<fbl::unique_ptr<Metadata>, Metadata::Node> metadata;
+
+ fbl::unique_ptr<zx_device_prop_t[]> props;
+
+ // Allocation backing |name| and |libname|
+ fbl::unique_ptr<char[]> name_alloc_;
+
+ // The AddRef and Release functions follow the contract for fbl::RefPtr.
+ void AddRef() const {
+ ++refcount_;
+ }
+
+ // Returns true when the last reference has been released.
+ bool Release() const {
+ const int32_t rc = refcount_;
+ --refcount_;
+ return rc == 1;
+ }
+};
+
+} // namespace devmgr
diff --git a/system/core/devmgr/devmgr/main.cpp b/system/core/devmgr/devmgr/main.cpp
index 200bb99..2eb9a31 100644
--- a/system/core/devmgr/devmgr/main.cpp
+++ b/system/core/devmgr/devmgr/main.cpp
@@ -28,6 +28,7 @@
#include <zircon/syscalls/object.h>
#include <zircon/syscalls/policy.h>
+#include <lib/async-loop/cpp/loop.h>
#include <lib/devmgr-launcher/processargs.h>
#include <lib/fdio/io.h>
#include <lib/fdio/namespace.h>
diff --git a/system/core/devmgr/rules.mk b/system/core/devmgr/rules.mk
index 3175cd8..91fbeb6 100644
--- a/system/core/devmgr/rules.mk
+++ b/system/core/devmgr/rules.mk
@@ -18,6 +18,7 @@
$(LOCAL_DIR)/devmgr/coordinator.cpp \
$(LOCAL_DIR)/devmgr/devfs.cpp \
$(LOCAL_DIR)/devmgr/devhost-loader-service.cpp \
+ $(LOCAL_DIR)/devmgr/device.cpp \
$(LOCAL_DIR)/devmgr/drivers.cpp \
$(LOCAL_DIR)/devmgr/fidl.cpp \
$(LOCAL_DIR)/shared/env.cpp \