blob: 3c65f4877bd664ef80c27e4e808a42f3c5651a89 [file] [log] [blame]
// Copyright 2016 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 <fs/managed-vfs.h>
#include <fbl/unique_ptr.h>
#include <lib/async/cpp/task.h>
#include <lib/sync/completion.h>
#include <utility>
namespace fs {
ManagedVfs::ManagedVfs() : is_shutting_down_(false) {}
ManagedVfs::ManagedVfs(async_dispatcher_t* dispatcher) : Vfs(dispatcher), is_shutting_down_(false) {}
ManagedVfs::~ManagedVfs() {
ZX_DEBUG_ASSERT(connections_.is_empty());
}
bool ManagedVfs::IsTerminated() const {
return is_shutting_down_ && connections_.is_empty();
}
// Asynchronously drop all connections.
void ManagedVfs::Shutdown(ShutdownCallback handler) {
ZX_DEBUG_ASSERT(handler);
zx_status_t status = async::PostTask(dispatcher(), [this, closure = std::move(handler)]() mutable {
ZX_DEBUG_ASSERT(!shutdown_handler_);
shutdown_handler_ = std::move(closure);
is_shutting_down_ = true;
UninstallAll(ZX_TIME_INFINITE);
// Signal the teardown on channels in a way that doesn't potentially
// pull them out from underneath async callbacks.
for (auto& c : connections_) {
c.AsyncTeardown();
}
CheckForShutdownComplete();
});
ZX_DEBUG_ASSERT(status == ZX_OK);
}
// Trigger "OnShutdownComplete" if all preconditions have been met.
void ManagedVfs::CheckForShutdownComplete() {
if (IsTerminated()) {
shutdown_task_.Post(dispatcher());
}
}
void ManagedVfs::OnShutdownComplete(async_dispatcher_t*, async::TaskBase*, zx_status_t status) {
ZX_ASSERT_MSG(IsTerminated(),
"Failed to complete VFS shutdown: dispatcher status = %d\n", status);
ZX_DEBUG_ASSERT(shutdown_handler_);
auto handler = std::move(shutdown_handler_);
handler(status);
}
void ManagedVfs::RegisterConnection(fbl::unique_ptr<Connection> connection) {
ZX_DEBUG_ASSERT(!is_shutting_down_);
connections_.push_back(std::move(connection));
}
void ManagedVfs::UnregisterConnection(Connection* connection) {
// We drop the result of |erase| on the floor, effectively destroying the
// connection when all other references (like async callbacks) have
// completed.
connections_.erase(*connection);
CheckForShutdownComplete();
}
bool ManagedVfs::IsTerminating() const {
return is_shutting_down_;
}
} // namespace fs