blob: bf4bb008fc4d4159bc92067ae2327c5eebb8cf67 [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.
#pragma once
#include <array>
#include <memory>
#include <queue>
#include <lib/async-loop/cpp/loop.h>
#include <lib/zx/job.h>
#include "lib/fxl/files/unique_fd.h"
#include "lib/fxl/macros.h"
#include "lib/fxl/strings/string_view.h"
#include "exception_port.h"
#include "io_loop.h"
#include "process.h"
#include "thread.h"
namespace inferior_control {
// Server implements the main loop and handles commands.
//
// NOTE: This class is generally not thread safe. Care must be taken when
// calling methods such as set_current_process() and SetCurrentThread()
// which modify its internal state.
class Server : public Process::Delegate {
public:
// Starts the main loop, and returns when the main loop exits.
// Returns true if the main loop exits cleanly, or false in the case of an
// error.
// TODO(armansito): More clearly define the error scenario.
// TODO(dje): This mightn't need to be virtual, but it provides consistency
// among the uses.
virtual bool Run() = 0;
zx_handle_t job_for_search() const { return job_for_search_.get(); }
zx_handle_t job_for_launch() const { return job_for_launch_.get(); }
// Returns a raw pointer to the current inferior. The instance pointed to by
// the returned pointer is owned by this Server instance and should not be
// deleted.
Process* current_process() const { return current_process_.get(); }
// Sets the current process. This cleans up the current process (if any) and
// takes ownership of |process|.
void set_current_process(Process* process) {
current_process_.reset(process);
}
// Returns a raw pointer to the current thread.
Thread* current_thread() const { return current_thread_.get(); }
// Assigns the current thread.
void SetCurrentThread(Thread* thread);
// Returns a mutable reference to the main message loop. The returned instance
// is owned by this Server instance and should not be deleted.
async::Loop& message_loop() { return message_loop_; }
// Returns a mutable reference to the exception port. The returned instance is
// owned by this Server instance and should not be deleted.
ExceptionPort& exception_port() { return exception_port_; }
// Call this to schedule termination of the server.
// N.B. The Server will exit its main loop asynchronously so any
// subsequently posted tasks will be dropped.
void PostQuitMessageLoop(bool status);
private:
// Returns a borrowed handle of the job whose processes we may attach to.
// If this is ZX_HANDLE_INVALID then we may not attach to any process.
zx::job job_for_search_;
// Returns a borrowed handle of the job where processes are launched.
// This is not necessarily |job_for_search_|, we may be able to attach to
// any process but not necessarily want to start new processes in the root
// job itself. If this is ZX_HANDLE_INVALID then starting new processes is
// not allowed.
zx::job job_for_launch_;
protected:
Server(zx::job job_for_search, zx::job job_for_launch);
virtual ~Server();
// Sets the run status and quits the main message loop.
void QuitMessageLoop(bool status);
// The current thread under debug. We only keep a weak pointer here, since the
// instance itself is owned by a Process and may get removed.
fxl::WeakPtr<Thread> current_thread_;
// The main loop.
async::Loop message_loop_;
// The ExceptionPort used by inferiors to receive exceptions.
// (This is declared after |message_loop_| since that needs to have been
// created before this can be initialized).
ExceptionPort exception_port_;
// Strong pointer to the current inferior process that is being debugged.
// NOTE: This must be declared after |exception_port_| above, since the
// process may do work in its destructor to detach itself from
// |exception_port_|.
std::unique_ptr<Process> current_process_;
// Stores the global error state. This is used to determine the return value
// for "Run()" when |message_loop_| exits.
bool run_status_;
private:
FXL_DISALLOW_COPY_AND_ASSIGN(Server);
};
// Same as Server, but provides I/O support.
// An example use-case is debugserver for gdb.
class ServerWithIO : public Server, public IOLoop::Delegate {
protected:
ServerWithIO(zx::job job_for_search, zx::job job_for_launch);
virtual ~ServerWithIO();
// The IOLoop used for blocking I/O operations over |client_sock_|.
// |message_loop_| and |client_sock_| both MUST outlive |io_loop_|. We take
// care to clean it up in the destructor.
std::unique_ptr<IOLoop> io_loop_;
// File descriptor for the socket (or terminal) used for communication.
// TODO(dje): Rename from *sock* after things are working.
fxl::UniqueFD client_sock_;
};
} // namespace inferior_control