blob: 65439d9c8c0a358294bc9329e8da619db716f238 [file] [log] [blame]
// 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 "peridot/lib/util/pseudo_dir_server.h"
namespace modular {
PseudoDirServer::PseudoDirServer(std::unique_ptr<vfs::PseudoDir> pseudo_dir)
: pseudo_dir_(std::move(pseudo_dir)),
serving_thread_(
[this](fidl::InterfaceRequest<fuchsia::io::Directory> request) {
StartThread(std::move(request));
},
dir_.NewRequest()) {
// Block until the run loop in |serving_thread_| is ready before returning
// control to the caller.
std::unique_lock<std::mutex> lock(ready_mutex_);
thread_loop_ready_.wait(lock, [this] { return thread_loop_ != nullptr; });
}
PseudoDirServer::~PseudoDirServer() {
FXL_CHECK(thread_loop_);
// std::thread requires that we join() the thread before it is destroyed.
thread_loop_->Quit();
serving_thread_.join();
}
// Opens a read-only FD at |path|. Path must not begin with '/'.
fxl::UniqueFD PseudoDirServer::OpenAt(std::string path) {
fuchsia::io::NodePtr node;
dir_->Open(fuchsia::io::OPEN_RIGHT_READABLE |
fuchsia::io::OPEN_FLAG_DESCRIBE, // flags
0u, // mode
path, node.NewRequest());
return fsl::OpenChannelAsFileDescriptor(node.Unbind().TakeChannel());
}
// This method is the handler for a new thread. It lets the owning thread know
// that it has started and serves a directory requests. The thread is exited
// when this object is destroyed.
void PseudoDirServer::StartThread(
fidl::InterfaceRequest<fuchsia::io::Directory> request) {
async::Loop loop(&kAsyncLoopConfigAttachToThread);
{
std::lock_guard<std::mutex> lock(ready_mutex_);
// Setting this will let |thread_loop_ready_.wait()| proceed.
thread_loop_ = &loop;
pseudo_dir_->Serve(fuchsia::io::OPEN_RIGHT_READABLE, request.TakeChannel());
thread_loop_ready_.notify_one();
}
thread_loop_->Run();
// This thread exits when the owner thread calls thread_loop_->Quit().
}
} // namespace modular