diff --git a/zircon/system/core/devmgr/devcoordinator/device.cpp b/zircon/system/core/devmgr/devcoordinator/device.cpp index ffd62ee5335d39766567cb8e9f9f3c790bec5cae..ac03e06194cd14e27f021e980855f087a9cb1924 100644 --- a/zircon/system/core/devmgr/devcoordinator/device.cpp +++ b/zircon/system/core/devmgr/devcoordinator/device.cpp @@ -11,6 +11,7 @@ #include "coordinator.h" #include "devfs.h" #include "fidl.h" +#include "suspend-task.h" namespace devmgr { @@ -193,6 +194,17 @@ zx_status_t Device::SignalReadyForBind(zx::duration delay) { return publish_task_.PostDelayed(this->coordinator->dispatcher(), delay); } +fbl::RefPtr<SuspendTask> Device::RequestSuspendTask(uint32_t suspend_flags) { + if (active_suspend_) { + // We don't support different types of suspends concurrently, and + // shouldn't be able to reach this state. + ZX_ASSERT(suspend_flags == active_suspend_->suspend_flags()); + } else { + active_suspend_ = SuspendTask::Create(fbl::WrapRefPtr(this), suspend_flags); + } + return active_suspend_; +} + zx_status_t Device::SendSuspend(uint32_t flags, SuspendCompletion completion) { if (suspend_completion_) { // We already have a pending suspend @@ -212,6 +224,7 @@ void Device::CompleteSuspend(zx_status_t status) { state_ = Device::State::kSuspended; } + active_suspend_ = nullptr; SuspendCompletion completion(std::move(suspend_completion_)); if (completion) { completion(status); diff --git a/zircon/system/core/devmgr/devcoordinator/device.h b/zircon/system/core/devmgr/devcoordinator/device.h index 9caa7628bc82827036fd5d289fe6e63b024c04ec..6dcfaa60b4408b639af920700a415254ab5a6c8c 100644 --- a/zircon/system/core/devmgr/devcoordinator/device.h +++ b/zircon/system/core/devmgr/devcoordinator/device.h @@ -24,6 +24,7 @@ class Coordinator; class Devhost; struct Devnode; class SuspendContext; +class SuspendTask; // clang-format off @@ -252,6 +253,9 @@ struct Device : public fbl::RefCounted<Device>, public AsyncLoopRefCountedRpcHan State state() const { return state_; } + // Creates a new suspend task if necessary and returns a reference to it. + // If one is already in-progress, a reference to it is returned instead + fbl::RefPtr<SuspendTask> RequestSuspendTask(uint32_t suspend_flags); private: zx_status_t HandleRead(); @@ -289,8 +293,11 @@ private: // The current state of the device State state_ = State::kActive; + // If a suspend is in-progress, this task represents it. + fbl::RefPtr<SuspendTask> active_suspend_; // If a suspend is in-progress, this completion will be invoked when it is - // completed. + // completed. It will likely mark |active_suspend_| as completed and clear + // it. SuspendCompletion suspend_completion_; }; diff --git a/zircon/system/core/devmgr/devcoordinator/suspend-task.cpp b/zircon/system/core/devmgr/devcoordinator/suspend-task.cpp index 6035380c15cd33bb97e95c61794dbec58daec45c..2821d3d581344f0d9e74aaf5f2928bbf5a925919 100644 --- a/zircon/system/core/devmgr/devcoordinator/suspend-task.cpp +++ b/zircon/system/core/devmgr/devcoordinator/suspend-task.cpp @@ -28,8 +28,8 @@ void SuspendTask::Run() { case Device::State::kSuspended: continue; case Device::State::kActive: break; } - auto task = SuspendTask::Create(fbl::WrapRefPtr(&child), flags_); - AddDependency(std::move(task)); + + AddDependency(child.RequestSuspendTask(flags_)); found_more_dependencies = true; } if (found_more_dependencies) { @@ -42,8 +42,7 @@ void SuspendTask::Run() { switch (device_->proxy->state()) { case Device::State::kSuspended: break; case Device::State::kActive: { - auto task = SuspendTask::Create(device_->proxy, flags_); - AddDependency(std::move(task)); + AddDependency(device_->proxy->RequestSuspendTask(flags_)); return; } } diff --git a/zircon/system/core/devmgr/devcoordinator/suspend-task.h b/zircon/system/core/devmgr/devcoordinator/suspend-task.h index 96f2b676dbf03f0e9d1ca843e19e8381c28fecc2..4d781af29fd7261132ae0a9e1cb378185ac6e996 100644 --- a/zircon/system/core/devmgr/devcoordinator/suspend-task.h +++ b/zircon/system/core/devmgr/devcoordinator/suspend-task.h @@ -17,6 +17,8 @@ public: // Don/t invoke this, use Create SuspendTask(fbl::RefPtr<Device> device, uint32_t flags, Completion completion); + uint32_t suspend_flags() { return flags_; } + ~SuspendTask() final; private: void Run() final;