llvm-project/lldb/tools/lldb-vscode/RunInTerminal.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

130 lines
3.5 KiB
C
Raw Normal View History

[vscode] Improve runInTerminal and support linux Depends on D93874. runInTerminal was using --wait-for, but it was some problems because it uses process polling looking for a single instance of the debuggee: - it gets to know of the target late, which renders breakpoints in the main function almost impossible - polling might fail if there are already other processes with the same name - polling might also fail on some linux machine, as it's implemented with the ps command, and the ps command's args and output are not standard everywhere As a better way to implement this so that it works well on Darwin and Linux, I'm using now the following process: - lldb-vscode notices the runInTerminal, so it spawns lldb-vscode with a special flag --launch-target <target>. This flags tells lldb-vscode to wait to be attached and then it execs the target program. I'm using lldb-vscode itself to do this, because it makes finding the launcher program easier. Also no CMAKE INSTALL scripts are needed. - Besides this, the debugger creates a temporary FIFO file where the launcher program will write its pid to. That way the debugger will be sure of which program to attach. - Once attach happend, the debugger creates a second temporary file to notify the launcher program that it has been attached, so that it can then exec. I'm using this instead of using a signal or a similar mechanism because I don't want the launcher program to wait indefinitely to be attached in case the debugger crashed. That would pollute the process list with a lot of hanging processes. Instead, I'm setting a 20 seconds timeout (that's an overkill) and the launcher program seeks in intervals the second tepmorary file. Some notes: - I preferred not to use sockets because it requires a lot of code and I only need a pid. It would also require a lot of code when windows support is implemented. - I didn't add Windows support, as I don't have a windows machine, but adding support for it should be easy, as the FIFO file can be implemented with a named pipe, which is standard on Windows and works pretty much the same way. The existing test which didn't pass on Linux, now passes. Differential Revision: https://reviews.llvm.org/D93951
2020-12-29 04:00:47 +08:00
//===-- RunInTerminal.h ----------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLDB_TOOLS_LLDB_VSCODE_RUNINTERMINAL_H
#define LLDB_TOOLS_LLDB_VSCODE_RUNINTERMINAL_H
#include "FifoFiles.h"
#include <future>
#include <thread>
namespace lldb_vscode {
enum RunInTerminalMessageKind {
eRunInTerminalMessageKindPID = 0,
eRunInTerminalMessageKindError,
eRunInTerminalMessageKindDidAttach,
};
struct RunInTerminalMessage;
struct RunInTerminalMessagePid;
struct RunInTerminalMessageError;
struct RunInTerminalMessageDidAttach;
struct RunInTerminalMessage {
RunInTerminalMessage(RunInTerminalMessageKind kind);
virtual ~RunInTerminalMessage() = default;
/// Serialize this object to JSON
virtual llvm::json::Value ToJSON() const = 0;
const RunInTerminalMessagePid *GetAsPidMessage() const;
const RunInTerminalMessageError *GetAsErrorMessage() const;
RunInTerminalMessageKind kind;
};
using RunInTerminalMessageUP = std::unique_ptr<RunInTerminalMessage>;
struct RunInTerminalMessagePid : RunInTerminalMessage {
RunInTerminalMessagePid(lldb::pid_t pid);
llvm::json::Value ToJSON() const override;
lldb::pid_t pid;
};
struct RunInTerminalMessageError : RunInTerminalMessage {
RunInTerminalMessageError(llvm::StringRef error);
llvm::json::Value ToJSON() const override;
std::string error;
};
struct RunInTerminalMessageDidAttach : RunInTerminalMessage {
RunInTerminalMessageDidAttach();
llvm::json::Value ToJSON() const override;
};
class RunInTerminalLauncherCommChannel {
public:
RunInTerminalLauncherCommChannel(llvm::StringRef comm_file);
/// Wait until the debug adaptor attaches.
///
/// \param[in] timeout
/// How long to wait to be attached.
//
/// \return
/// An \a llvm::Error object in case of errors or if this operation times
/// out.
llvm::Error WaitUntilDebugAdaptorAttaches(std::chrono::milliseconds timeout);
/// Notify the debug adaptor this process' pid.
///
/// \return
/// An \a llvm::Error object in case of errors or if this operation times
/// out.
llvm::Error NotifyPid();
/// Notify the debug adaptor that there's been an error.
void NotifyError(llvm::StringRef error);
private:
FifoFileIO m_io;
};
class RunInTerminalDebugAdapterCommChannel {
public:
RunInTerminalDebugAdapterCommChannel(llvm::StringRef comm_file);
/// Notify the runInTerminal launcher that it was attached.
///
/// \return
/// A future indicated whether the runInTerminal launcher received the
/// message correctly or not.
std::future<lldb::SBError> NotifyDidAttach();
[vscode] Improve runInTerminal and support linux Depends on D93874. runInTerminal was using --wait-for, but it was some problems because it uses process polling looking for a single instance of the debuggee: - it gets to know of the target late, which renders breakpoints in the main function almost impossible - polling might fail if there are already other processes with the same name - polling might also fail on some linux machine, as it's implemented with the ps command, and the ps command's args and output are not standard everywhere As a better way to implement this so that it works well on Darwin and Linux, I'm using now the following process: - lldb-vscode notices the runInTerminal, so it spawns lldb-vscode with a special flag --launch-target <target>. This flags tells lldb-vscode to wait to be attached and then it execs the target program. I'm using lldb-vscode itself to do this, because it makes finding the launcher program easier. Also no CMAKE INSTALL scripts are needed. - Besides this, the debugger creates a temporary FIFO file where the launcher program will write its pid to. That way the debugger will be sure of which program to attach. - Once attach happend, the debugger creates a second temporary file to notify the launcher program that it has been attached, so that it can then exec. I'm using this instead of using a signal or a similar mechanism because I don't want the launcher program to wait indefinitely to be attached in case the debugger crashed. That would pollute the process list with a lot of hanging processes. Instead, I'm setting a 20 seconds timeout (that's an overkill) and the launcher program seeks in intervals the second tepmorary file. Some notes: - I preferred not to use sockets because it requires a lot of code and I only need a pid. It would also require a lot of code when windows support is implemented. - I didn't add Windows support, as I don't have a windows machine, but adding support for it should be easy, as the FIFO file can be implemented with a named pipe, which is standard on Windows and works pretty much the same way. The existing test which didn't pass on Linux, now passes. Differential Revision: https://reviews.llvm.org/D93951
2020-12-29 04:00:47 +08:00
/// Fetch the pid of the runInTerminal launcher.
///
/// \return
/// An \a llvm::Error object in case of errors or if this operation times
/// out.
llvm::Expected<lldb::pid_t> GetLauncherPid();
/// Fetch any errors emitted by the runInTerminal launcher or return a
/// default error message if a certain timeout if reached.
std::string GetLauncherError();
private:
FifoFileIO m_io;
};
/// Create a fifo file used to communicate the debug adaptor with
/// the runInTerminal launcher.
llvm::Expected<std::shared_ptr<FifoFile>> CreateRunInTerminalCommFile();
} // namespace lldb_vscode
#endif // LLDB_TOOLS_LLDB_VSCODE_RUNINTERMINAL_H