blob: 95e32aa73ecf06e2019b4487eefcfc83eeed39d9 [file] [log] [blame] [edit]
// Copyright 2020 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.
#ifndef SRC_DEVELOPER_SHELL_CONSOLE_SCOPED_INTERPRETER_H_
#define SRC_DEVELOPER_SHELL_CONSOLE_SCOPED_INTERPRETER_H_
#include <unistd.h>
#include <zircon/status.h>
#include <condition_variable>
#include <mutex>
#include <thread>
#include "src/developer/shell/interpreter/src/server.h"
namespace shell::console {
// This class creates a separate thread running an interpreter with a managed lifetime.
// If a client wants to communicate with that interpreter, it should call |client()|.
class ScopedInterpreter {
public:
ScopedInterpreter() {
zx_handle_t client_ch;
zx_handle_t server_ch;
zx_channel_create(0, &client_ch, &server_ch);
server_loop_ = nullptr;
// In the long run, we want to talk with a server component. There is currently (components v1)
// no way to make sure that the server component gets the correct permissions from this program.
// So, we start a server in a separate thread, and talk with that.
// std::thread t();
server_thread_ = std::thread([this, server_ch]() {
shell::interpreter::server::Server server;
{
std::unique_lock<std::mutex> lck(mutex_);
server_loop_ = server.loop();
condvar_.notify_all();
}
zx_status_t result = server.IncomingConnection(server_ch);
if (result != ZX_OK) {
fprintf(stderr, "Unable to start interpreter: %s\n", zx_status_get_string(result));
exit(1);
}
server.Run();
});
zx::channel client_channel(client_ch);
client_ = std::make_unique<llcpp::fuchsia::shell::Shell::SyncClient>(std::move(client_channel));
}
~ScopedInterpreter() {
async::Loop* sl;
{
// Wait for server thread startup to finish, if it hasn't.
std::unique_lock<std::mutex> lck(mutex_);
// Loop is for spurious wakeups.
while ((sl = server_loop_) == nullptr) {
condvar_.wait(lck);
}
}
// Shutdown the loop and wait for the server thread to notice.
if (sl != nullptr) {
sl->Quit();
server_thread_.join();
}
}
// Returns a pointer to the SyncClient that is valid during the lifetime of this object.
llcpp::fuchsia::shell::Shell::SyncClient* client() { return client_.get(); }
private:
async::Loop* server_loop_ = nullptr;
std::thread server_thread_;
std::unique_ptr<llcpp::fuchsia::shell::Shell::SyncClient> client_;
std::mutex mutex_;
std::condition_variable condvar_;
};
} // namespace shell::console
#endif // SRC_DEVELOPER_SHELL_CONSOLE_SCOPED_INTERPRETER_H_