https://github.com/SuibianP created 
https://github.com/llvm/llvm-project/pull/142374

`runInTerminal` is currently implemented using JSON messages over FIFOs, which 
feels too clunky for the simple job of passing a PID.

Instead, take advantage of `si_pid` available from `sa_sigaction` handler, and 
send a user signal instead. Both synchronisation and timeout are preserved with 
the protocol below,

1. Debugger waits for `SIGUSR1` under timeout with pselect
2. Launcher forks into child, sends `SIGUSR1` to debugger and suspends
3. Debugger receives `SIGUSR1`, captures the sender (launcher child) PID, 
attaches to and resumes it
4. Launcher child resumes and `exec`'s into target
5. Launcher parent `waitpid`'s and kills irresponsive child after timeout

With this, the entirety of `FifoFiles` and `RunInTerminal` can be dropped.

Refs: https://github.com/llvm/llvm-project/pull/121269#issuecomment-2901401482

>From 5a1b7ee1f33f6fcb115a1a9f468b66391612851a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jialun=20Hu=20=EF=BC=88=E8=83=A1=E4=BD=B3=E4=BC=A6?=
 =?UTF-8?q?=EF=BC=89?= <jialun...@razer.com>
Date: Mon, 2 Jun 2025 16:16:11 +0800
Subject: [PATCH] [lldb-dap] Reimplement runInTerminal with signals

runInTerminal is currently implemented using JSON messages over FIFOs,
which feels too clunky for the simple job of passing a PID.

Instead, take advantage of si_pid available from sa_sigaction handler,
and send a user signal instead. Both synchronisation and timeout are
preserved with the protocol below,

1. Debugger waits for SIGUSR1 under timeout with pselect
2. Launcher forks into child, sends SIGUSR1 to debugger and suspends
3. Debugger receives SIGUSR1, captures the sender (launcher child) PID,
   attaches to and resumes it
4. Launcher child resumes and exec's into target
5. Launcher parent waitpid's and kills irresponsive child after timeout

With this, the entirety of FifoFiles and RunInTerminal can be dropped.

Refs: https://github.com/llvm/llvm-project/pull/121269#issuecomment-2901401482
---
 .../runInTerminal/TestDAP_runInTerminal.py    | 117 ------------
 lldb/tools/lldb-dap/CMakeLists.txt            |   2 -
 lldb/tools/lldb-dap/FifoFiles.cpp             | 101 -----------
 lldb/tools/lldb-dap/FifoFiles.h               |  85 ---------
 .../tools/lldb-dap/Handler/RequestHandler.cpp |  99 +++++++---
 lldb/tools/lldb-dap/JSONUtils.cpp             |   5 +-
 lldb/tools/lldb-dap/JSONUtils.h               |   5 +-
 lldb/tools/lldb-dap/Options.td                |  15 +-
 lldb/tools/lldb-dap/RunInTerminal.cpp         | 170 ------------------
 lldb/tools/lldb-dap/RunInTerminal.h           | 131 --------------
 lldb/tools/lldb-dap/tool/lldb-dap.cpp         |  87 +++++----
 11 files changed, 123 insertions(+), 694 deletions(-)
 delete mode 100644 lldb/tools/lldb-dap/FifoFiles.cpp
 delete mode 100644 lldb/tools/lldb-dap/FifoFiles.h
 delete mode 100644 lldb/tools/lldb-dap/RunInTerminal.cpp
 delete mode 100644 lldb/tools/lldb-dap/RunInTerminal.h

diff --git 
a/lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py 
b/lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py
index 65c931210d400..3b6571621e541 100644
--- a/lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py
+++ b/lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py
@@ -131,120 +131,3 @@ def test_runInTerminalInvalidTarget(self):
             "'INVALIDPROGRAM' does not exist",
             response["body"]["error"]["format"],
         )
-
-    @skipIfWindows
-    @skipIf(oslist=["linux"], archs=no_match(["x86_64"]))
-    def test_missingArgInRunInTerminalLauncher(self):
-        if not self.isTestSupported():
-            return
-        proc = subprocess.run(
-            [self.lldbDAPExec, "--launch-target", "INVALIDPROGRAM"],
-            capture_output=True,
-            universal_newlines=True,
-        )
-        self.assertNotEqual(proc.returncode, 0)
-        self.assertIn(
-            '"--launch-target" requires "--comm-file" to be specified', 
proc.stderr
-        )
-
-    @skipIfWindows
-    @skipIf(oslist=["linux"], archs=no_match(["x86_64"]))
-    def test_FakeAttachedRunInTerminalLauncherWithInvalidProgram(self):
-        if not self.isTestSupported():
-            return
-        comm_file = os.path.join(self.getBuildDir(), "comm-file")
-        os.mkfifo(comm_file)
-
-        proc = subprocess.Popen(
-            [
-                self.lldbDAPExec,
-                "--comm-file",
-                comm_file,
-                "--launch-target",
-                "INVALIDPROGRAM",
-            ],
-            universal_newlines=True,
-            stderr=subprocess.PIPE,
-        )
-
-        self.readPidMessage(comm_file)
-        self.sendDidAttachMessage(comm_file)
-        self.assertIn("No such file or directory", 
self.readErrorMessage(comm_file))
-
-        _, stderr = proc.communicate()
-        self.assertIn("No such file or directory", stderr)
-
-    @skipIfWindows
-    @skipIf(oslist=["linux"], archs=no_match(["x86_64"]))
-    def test_FakeAttachedRunInTerminalLauncherWithValidProgram(self):
-        if not self.isTestSupported():
-            return
-        comm_file = os.path.join(self.getBuildDir(), "comm-file")
-        os.mkfifo(comm_file)
-
-        proc = subprocess.Popen(
-            [
-                self.lldbDAPExec,
-                "--comm-file",
-                comm_file,
-                "--launch-target",
-                "echo",
-                "foo",
-            ],
-            universal_newlines=True,
-            stdout=subprocess.PIPE,
-        )
-
-        self.readPidMessage(comm_file)
-        self.sendDidAttachMessage(comm_file)
-
-        stdout, _ = proc.communicate()
-        self.assertIn("foo", stdout)
-
-    @skipIfWindows
-    @skipIf(oslist=["linux"], archs=no_match(["x86_64"]))
-    def test_FakeAttachedRunInTerminalLauncherAndCheckEnvironment(self):
-        if not self.isTestSupported():
-            return
-        comm_file = os.path.join(self.getBuildDir(), "comm-file")
-        os.mkfifo(comm_file)
-
-        proc = subprocess.Popen(
-            [self.lldbDAPExec, "--comm-file", comm_file, "--launch-target", 
"env"],
-            universal_newlines=True,
-            stdout=subprocess.PIPE,
-            env={**os.environ, "FOO": "BAR"},
-        )
-
-        self.readPidMessage(comm_file)
-        self.sendDidAttachMessage(comm_file)
-
-        stdout, _ = proc.communicate()
-        self.assertIn("FOO=BAR", stdout)
-
-    @skipIfWindows
-    @skipIf(oslist=["linux"], archs=no_match(["x86_64"]))
-    def test_NonAttachedRunInTerminalLauncher(self):
-        if not self.isTestSupported():
-            return
-        comm_file = os.path.join(self.getBuildDir(), "comm-file")
-        os.mkfifo(comm_file)
-
-        proc = subprocess.Popen(
-            [
-                self.lldbDAPExec,
-                "--comm-file",
-                comm_file,
-                "--launch-target",
-                "echo",
-                "foo",
-            ],
-            universal_newlines=True,
-            stderr=subprocess.PIPE,
-            env={**os.environ, "LLDB_DAP_RIT_TIMEOUT_IN_MS": "1000"},
-        )
-
-        self.readPidMessage(comm_file)
-
-        _, stderr = proc.communicate()
-        self.assertIn("Timed out trying to get messages from the debug 
adapter", stderr)
diff --git a/lldb/tools/lldb-dap/CMakeLists.txt 
b/lldb/tools/lldb-dap/CMakeLists.txt
index 40cba16c141f0..3e7e88afa9ced 100644
--- a/lldb/tools/lldb-dap/CMakeLists.txt
+++ b/lldb/tools/lldb-dap/CMakeLists.txt
@@ -14,7 +14,6 @@ add_lldb_library(lldbDAP
   DAPLog.cpp
   EventHelper.cpp
   ExceptionBreakpoint.cpp
-  FifoFiles.cpp
   FunctionBreakpoint.cpp
   InstructionBreakpoint.cpp
   JSONUtils.cpp
@@ -22,7 +21,6 @@ add_lldb_library(lldbDAP
   OutputRedirector.cpp
   ProgressEvent.cpp
   ProtocolUtils.cpp
-  RunInTerminal.cpp
   SourceBreakpoint.cpp
   Transport.cpp
   Variables.cpp
diff --git a/lldb/tools/lldb-dap/FifoFiles.cpp 
b/lldb/tools/lldb-dap/FifoFiles.cpp
deleted file mode 100644
index 1f1bba80bd3b1..0000000000000
--- a/lldb/tools/lldb-dap/FifoFiles.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-//===-- FifoFiles.cpp -------------------------------------------*- 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "FifoFiles.h"
-#include "JSONUtils.h"
-
-#if !defined(_WIN32)
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#endif
-
-#include <chrono>
-#include <fstream>
-#include <future>
-#include <optional>
-
-using namespace llvm;
-
-namespace lldb_dap {
-
-FifoFile::FifoFile(StringRef path) : m_path(path) {}
-
-FifoFile::~FifoFile() {
-#if !defined(_WIN32)
-  unlink(m_path.c_str());
-#endif
-}
-
-Expected<std::shared_ptr<FifoFile>> CreateFifoFile(StringRef path) {
-#if defined(_WIN32)
-  return createStringError(inconvertibleErrorCode(), "Unimplemented");
-#else
-  if (int err = mkfifo(path.data(), 0600))
-    return createStringError(std::error_code(err, std::generic_category()),
-                             "Couldn't create fifo file: %s", path.data());
-  return std::make_shared<FifoFile>(path);
-#endif
-}
-
-FifoFileIO::FifoFileIO(StringRef fifo_file, StringRef other_endpoint_name)
-    : m_fifo_file(fifo_file), m_other_endpoint_name(other_endpoint_name) {}
-
-Expected<json::Value> FifoFileIO::ReadJSON(std::chrono::milliseconds timeout) {
-  // We use a pointer for this future, because otherwise its normal destructor
-  // would wait for the getline to end, rendering the timeout useless.
-  std::optional<std::string> line;
-  std::future<void> *future =
-      new std::future<void>(std::async(std::launch::async, [&]() {
-        std::ifstream reader(m_fifo_file, std::ifstream::in);
-        std::string buffer;
-        std::getline(reader, buffer);
-        if (!buffer.empty())
-          line = buffer;
-      }));
-  if (future->wait_for(timeout) == std::future_status::timeout || !line)
-    // Indeed this is a leak, but it's intentional. "future" obj destructor
-    //  will block on waiting for the worker thread to join. And the worker
-    //  thread might be stuck in blocking I/O. Intentionally leaking the  obj
-    //  as a hack to avoid blocking main thread, and adding annotation to
-    //  supress static code inspection warnings
-
-    // coverity[leaked_storage]
-    return createStringError(inconvertibleErrorCode(),
-                             "Timed out trying to get messages from the " +
-                                 m_other_endpoint_name);
-  delete future;
-  return json::parse(*line);
-}
-
-Error FifoFileIO::SendJSON(const json::Value &json,
-                           std::chrono::milliseconds timeout) {
-  bool done = false;
-  std::future<void> *future =
-      new std::future<void>(std::async(std::launch::async, [&]() {
-        std::ofstream writer(m_fifo_file, std::ofstream::out);
-        writer << JSONToString(json) << std::endl;
-        done = true;
-      }));
-  if (future->wait_for(timeout) == std::future_status::timeout || !done) {
-    // Indeed this is a leak, but it's intentional. "future" obj destructor 
will
-    // block on waiting for the worker thread to join. And the worker thread
-    // might be stuck in blocking I/O. Intentionally leaking the  obj as a hack
-    // to avoid blocking main thread, and adding annotation to supress static
-    // code inspection warnings"
-
-    // coverity[leaked_storage]
-    return createStringError(inconvertibleErrorCode(),
-                             "Timed out trying to send messages to the " +
-                                 m_other_endpoint_name);
-  }
-  delete future;
-  return Error::success();
-}
-
-} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/FifoFiles.h b/lldb/tools/lldb-dap/FifoFiles.h
deleted file mode 100644
index 633ebeb2aedd4..0000000000000
--- a/lldb/tools/lldb-dap/FifoFiles.h
+++ /dev/null
@@ -1,85 +0,0 @@
-//===-- FifoFiles.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_DAP_FIFOFILES_H
-#define LLDB_TOOLS_LLDB_DAP_FIFOFILES_H
-
-#include "llvm/Support/Error.h"
-#include "llvm/Support/JSON.h"
-
-#include <chrono>
-
-namespace lldb_dap {
-
-/// Struct that controls the life of a fifo file in the filesystem.
-///
-/// The file is destroyed when the destructor is invoked.
-struct FifoFile {
-  FifoFile(llvm::StringRef path);
-
-  ~FifoFile();
-
-  std::string m_path;
-};
-
-/// Create a fifo file in the filesystem.
-///
-/// \param[in] path
-///     The path for the fifo file.
-///
-/// \return
-///     A \a std::shared_ptr<FifoFile> if the file could be created, or an
-///     \a llvm::Error in case of failures.
-llvm::Expected<std::shared_ptr<FifoFile>> CreateFifoFile(llvm::StringRef path);
-
-class FifoFileIO {
-public:
-  /// \param[in] fifo_file
-  ///     The path to an input fifo file that exists in the file system.
-  ///
-  /// \param[in] other_endpoint_name
-  ///     A human readable name for the other endpoint that will communicate
-  ///     using this file. This is used for error messages.
-  FifoFileIO(llvm::StringRef fifo_file, llvm::StringRef other_endpoint_name);
-
-  /// Read the next JSON object from the underlying input fifo file.
-  ///
-  /// The JSON object is expected to be a single line delimited with \a
-  /// std::endl.
-  ///
-  /// \return
-  ///     An \a llvm::Error object indicating the success or failure of this
-  ///     operation. Failures arise if the timeout is hit, the next line of 
text
-  ///     from the fifo file is not a valid JSON object, or is it impossible to
-  ///     read from the file.
-  llvm::Expected<llvm::json::Value> ReadJSON(std::chrono::milliseconds 
timeout);
-
-  /// Serialize a JSON object and write it to the underlying output fifo file.
-  ///
-  /// \param[in] json
-  ///     The JSON object to send. It will be printed as a single line 
delimited
-  ///     with \a std::endl.
-  ///
-  /// \param[in] timeout
-  ///     A timeout for how long we should until for the data to be consumed.
-  ///
-  /// \return
-  ///     An \a llvm::Error object indicating whether the data was consumed by
-  ///     a reader or not.
-  llvm::Error SendJSON(
-      const llvm::json::Value &json,
-      std::chrono::milliseconds timeout = std::chrono::milliseconds(20000));
-
-private:
-  std::string m_fifo_file;
-  std::string m_other_endpoint_name;
-};
-
-} // namespace lldb_dap
-
-#endif // LLDB_TOOLS_LLDB_DAP_FIFOFILES_H
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
index 93bc80a38e29d..cfcbabbb16a93 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
@@ -14,10 +14,12 @@
 #include "LLDBUtils.h"
 #include "Protocol/ProtocolBase.h"
 #include "Protocol/ProtocolRequests.h"
-#include "RunInTerminal.h"
 #include "lldb/API/SBDefines.h"
 #include "lldb/API/SBEnvironment.h"
 #include "llvm/Support/Error.h"
+#include <cerrno>
+#include <csignal>
+#include <limits>
 #include <mutex>
 
 #if !defined(_WIN32)
@@ -51,6 +53,70 @@ static uint32_t SetLaunchFlag(uint32_t flags, bool flag,
   return flags;
 }
 
+// Assume single thread
+class PidReceiver {
+private:
+  inline static volatile std::sig_atomic_t pid;
+  sigset_t oldmask;
+  struct sigaction oldaction;
+
+  static_assert(std::numeric_limits<volatile sig_atomic_t>::max() >=
+                    std::numeric_limits<pid_t>::max(),
+                "sig_atomic_t must be able to hold a pid_t value");
+
+  static void sig_handler(int, siginfo_t *info, void *) {
+    // Store the PID from the signal info
+    pid = info->si_pid;
+  }
+
+  PidReceiver(const PidReceiver &) = delete;
+  PidReceiver &operator=(const PidReceiver &) = delete;
+  PidReceiver(PidReceiver &&) = delete;
+
+public:
+  PidReceiver() {
+    pid = LLDB_INVALID_PROCESS_ID;
+    // sigprocmask and sigaction can only fail by programmer error
+    // Defer SIGUSR1, otherwise we might receive it out of pselect and hang
+    sigset_t mask;
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGUSR1);
+    assert(!sigprocmask(SIG_BLOCK, &mask, &oldmask));
+
+    // Set up sigaction for SIGUSR1 with SA_SIGINFO
+    struct sigaction sa;
+    std::memset(&sa, 0, sizeof(sa));
+    sa.sa_sigaction = sig_handler;
+    sa.sa_flags = SA_SIGINFO;
+    sigemptyset(&sa.sa_mask);
+    assert(!sigaction(SIGUSR1, &sa, &oldaction));
+  }
+
+  ~PidReceiver() {
+    // Restore the old signal mask
+    assert(!sigprocmask(SIG_SETMASK, &oldmask, nullptr));
+    assert(!sigaction(SIGUSR1, &oldaction, nullptr));
+  }
+
+  llvm::Expected<lldb::pid_t> WaitForPid() {
+    // Wait for the signal to be received
+    while (pid == LLDB_INVALID_PROCESS_ID) {
+      struct timespec timeout;
+      timeout.tv_sec = 5;
+      timeout.tv_nsec = 0;
+      auto ret = pselect(0, nullptr, nullptr, nullptr, &timeout, &oldmask);
+      if (ret == -1 && errno != EINTR) {
+        return llvm::createStringError(
+            std::error_code(errno, std::generic_category()), "pselect failed");
+      } else if (ret == 0) {
+        return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                       "Timed out waiting for signal");
+      }
+    }
+    return pid;
+  }
+};
+
 static llvm::Error
 RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) {
   if (!dap.clientFeatures.contains(
@@ -65,26 +131,19 @@ RunInTerminal(DAP &dap, const 
protocol::LaunchRequestArguments &arguments) {
   dap.is_attach = true;
   lldb::SBAttachInfo attach_info;
 
-  llvm::Expected<std::shared_ptr<FifoFile>> comm_file_or_err =
-      CreateRunInTerminalCommFile();
-  if (!comm_file_or_err)
-    return comm_file_or_err.takeError();
-  FifoFile &comm_file = *comm_file_or_err.get();
-
-  RunInTerminalDebugAdapterCommChannel comm_channel(comm_file.m_path);
-
   lldb::pid_t debugger_pid = LLDB_INVALID_PROCESS_ID;
 #if !defined(_WIN32)
   debugger_pid = getpid();
 #endif
 
+  auto pid_receiver = PidReceiver();
   llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest(
       arguments.configuration.program, arguments.args, arguments.env,
-      arguments.cwd, comm_file.m_path, debugger_pid);
+      arguments.cwd, debugger_pid);
   dap.SendReverseRequest<LogFailureResponseHandler>("runInTerminal",
                                                     
std::move(reverse_request));
 
-  if (llvm::Expected<lldb::pid_t> pid = comm_channel.GetLauncherPid())
+  if (llvm::Expected<lldb::pid_t> pid = pid_receiver.WaitForPid())
     attach_info.SetProcessID(*pid);
   else
     return pid.takeError();
@@ -95,13 +154,7 @@ RunInTerminal(DAP &dap, const 
protocol::LaunchRequestArguments &arguments) {
 
   if (error.Fail())
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                   "Failed to attach to the target process. 
%s",
-                                   comm_channel.GetLauncherError().c_str());
-  // This will notify the runInTerminal launcher that we attached.
-  // We have to make this async, as the function won't return until the 
launcher
-  // resumes and reads the data.
-  std::future<lldb::SBError> did_attach_message_success =
-      comm_channel.NotifyDidAttach();
+                                   "Failed to attach to the target process.");
 
   // We just attached to the runInTerminal launcher, which was waiting to be
   // attached. We now resume it, so it can receive the didAttach notification
@@ -115,15 +168,7 @@ RunInTerminal(DAP &dap, const 
protocol::LaunchRequestArguments &arguments) {
   // we return the debugger to its sync state.
   scope_sync_mode.reset();
 
-  // If sending the notification failed, the launcher should be dead by now and
-  // the async didAttach notification should have an error message, so we
-  // return it. Otherwise, everything was a success.
-  did_attach_message_success.wait();
-  error = did_attach_message_success.get();
-  if (error.Success())
-    return llvm::Error::success();
-  return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                 error.GetCString());
+  return llvm::Error::success();
 }
 
 void BaseRequestHandler::Run(const Request &request) {
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp 
b/lldb/tools/lldb-dap/JSONUtils.cpp
index 573f3eba00f62..bf10742e18bb8 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -1238,15 +1238,14 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit 
&unit) {
 llvm::json::Object CreateRunInTerminalReverseRequest(
     llvm::StringRef program, const std::vector<std::string> &args,
     const llvm::StringMap<std::string> &env, llvm::StringRef cwd,
-    llvm::StringRef comm_file, lldb::pid_t debugger_pid) {
+    lldb::pid_t debugger_pid) {
   llvm::json::Object run_in_terminal_args;
   // This indicates the IDE to open an embedded terminal, instead of opening
   // the terminal in a new window.
   run_in_terminal_args.try_emplace("kind", "integrated");
 
   // The program path must be the first entry in the "args" field
-  std::vector<std::string> req_args = {DAP::debug_adapter_path.str(),
-                                       "--comm-file", comm_file.str()};
+  std::vector<std::string> req_args = {DAP::debug_adapter_path.str()};
   if (debugger_pid != LLDB_INVALID_PROCESS_ID) {
     req_args.push_back("--debugger-pid");
     req_args.push_back(std::to_string(debugger_pid));
diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h
index 08699a94bbd87..4ed66e6992be2 100644
--- a/lldb/tools/lldb-dap/JSONUtils.h
+++ b/lldb/tools/lldb-dap/JSONUtils.h
@@ -466,9 +466,6 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit 
&unit);
 /// \param[in] cwd
 ///     The working directory for the run in terminal request.
 ///
-/// \param[in] comm_file
-///     The fifo file used to communicate the with the target launcher.
-///
 /// \param[in] debugger_pid
 ///     The PID of the lldb-dap instance that will attach to the target. The
 ///     launcher uses it on Linux tell the kernel that it should allow the
@@ -480,7 +477,7 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit 
&unit);
 llvm::json::Object CreateRunInTerminalReverseRequest(
     llvm::StringRef program, const std::vector<std::string> &args,
     const llvm::StringMap<std::string> &env, llvm::StringRef cwd,
-    llvm::StringRef comm_file, lldb::pid_t debugger_pid);
+    lldb::pid_t debugger_pid);
 
 /// Create a "Terminated" JSON object that contains statistics
 ///
diff --git a/lldb/tools/lldb-dap/Options.td b/lldb/tools/lldb-dap/Options.td
index aecf91797ac70..669d6a7c0df05 100644
--- a/lldb/tools/lldb-dap/Options.td
+++ b/lldb/tools/lldb-dap/Options.td
@@ -31,16 +31,11 @@ def connection
           "Connections are specified like 'tcp://[host]:port' or "
           "'unix:///path'.">;
 
-def launch_target: S<"launch-target">,
-  MetaVarName<"<target>">,
-  HelpText<"Launch a target for the launchInTerminal request. Any argument "
-    "provided after this one will be passed to the target. The parameter "
-    "--comm-file must also be specified.">;
-
-def comm_file: S<"comm-file">,
-  MetaVarName<"<file>">,
-  HelpText<"The fifo file used to communicate the with the debug adapter "
-    "when using --launch-target.">;
+def launch_target
+    : S<"launch-target">,
+      MetaVarName<"<target>">,
+      HelpText<"Launch a target for the launchInTerminal request. Any argument 
"
+               "provided after this one will be passed to the target.">;
 
 def debugger_pid: S<"debugger-pid">,
   MetaVarName<"<pid>">,
diff --git a/lldb/tools/lldb-dap/RunInTerminal.cpp 
b/lldb/tools/lldb-dap/RunInTerminal.cpp
deleted file mode 100644
index 9f309dd78221a..0000000000000
--- a/lldb/tools/lldb-dap/RunInTerminal.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-//===-- RunInTerminal.cpp ---------------------------------------*- 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "RunInTerminal.h"
-#include "JSONUtils.h"
-
-#if !defined(_WIN32)
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#endif
-
-#include <chrono>
-#include <future>
-
-#include "llvm/Support/FileSystem.h"
-
-using namespace llvm;
-
-namespace lldb_dap {
-
-const RunInTerminalMessagePid *RunInTerminalMessage::GetAsPidMessage() const {
-  return static_cast<const RunInTerminalMessagePid *>(this);
-}
-
-const RunInTerminalMessageError *
-RunInTerminalMessage::GetAsErrorMessage() const {
-  return static_cast<const RunInTerminalMessageError *>(this);
-}
-
-RunInTerminalMessage::RunInTerminalMessage(RunInTerminalMessageKind kind)
-    : kind(kind) {}
-
-RunInTerminalMessagePid::RunInTerminalMessagePid(lldb::pid_t pid)
-    : RunInTerminalMessage(eRunInTerminalMessageKindPID), pid(pid) {}
-
-json::Value RunInTerminalMessagePid::ToJSON() const {
-  return json::Object{{"kind", "pid"}, {"pid", static_cast<int64_t>(pid)}};
-}
-
-RunInTerminalMessageError::RunInTerminalMessageError(StringRef error)
-    : RunInTerminalMessage(eRunInTerminalMessageKindError), error(error) {}
-
-json::Value RunInTerminalMessageError::ToJSON() const {
-  return json::Object{{"kind", "error"}, {"value", error}};
-}
-
-RunInTerminalMessageDidAttach::RunInTerminalMessageDidAttach()
-    : RunInTerminalMessage(eRunInTerminalMessageKindDidAttach) {}
-
-json::Value RunInTerminalMessageDidAttach::ToJSON() const {
-  return json::Object{{"kind", "didAttach"}};
-}
-
-static Expected<RunInTerminalMessageUP>
-ParseJSONMessage(const json::Value &json) {
-  if (const json::Object *obj = json.getAsObject()) {
-    if (std::optional<StringRef> kind = obj->getString("kind")) {
-      if (*kind == "pid") {
-        if (std::optional<int64_t> pid = obj->getInteger("pid"))
-          return std::make_unique<RunInTerminalMessagePid>(
-              static_cast<lldb::pid_t>(*pid));
-      } else if (*kind == "error") {
-        if (std::optional<StringRef> error = obj->getString("error"))
-          return std::make_unique<RunInTerminalMessageError>(*error);
-      } else if (*kind == "didAttach") {
-        return std::make_unique<RunInTerminalMessageDidAttach>();
-      }
-    }
-  }
-
-  return createStringError(inconvertibleErrorCode(),
-                           "Incorrect JSON message: " + JSONToString(json));
-}
-
-static Expected<RunInTerminalMessageUP>
-GetNextMessage(FifoFileIO &io, std::chrono::milliseconds timeout) {
-  if (Expected<json::Value> json = io.ReadJSON(timeout))
-    return ParseJSONMessage(*json);
-  else
-    return json.takeError();
-}
-
-static Error ToError(const RunInTerminalMessage &message) {
-  if (message.kind == eRunInTerminalMessageKindError)
-    return createStringError(inconvertibleErrorCode(),
-                             message.GetAsErrorMessage()->error);
-  return createStringError(inconvertibleErrorCode(),
-                           "Unexpected JSON message: " +
-                               JSONToString(message.ToJSON()));
-}
-
-RunInTerminalLauncherCommChannel::RunInTerminalLauncherCommChannel(
-    StringRef comm_file)
-    : m_io(comm_file, "debug adapter") {}
-
-Error RunInTerminalLauncherCommChannel::WaitUntilDebugAdapterAttaches(
-    std::chrono::milliseconds timeout) {
-  if (Expected<RunInTerminalMessageUP> message =
-          GetNextMessage(m_io, timeout)) {
-    if (message.get()->kind == eRunInTerminalMessageKindDidAttach)
-      return Error::success();
-    else
-      return ToError(*message.get());
-  } else
-    return message.takeError();
-}
-
-Error RunInTerminalLauncherCommChannel::NotifyPid() {
-  return m_io.SendJSON(RunInTerminalMessagePid(getpid()).ToJSON());
-}
-
-void RunInTerminalLauncherCommChannel::NotifyError(StringRef error) {
-  if (Error err = m_io.SendJSON(RunInTerminalMessageError(error).ToJSON(),
-                                std::chrono::seconds(2)))
-    llvm::errs() << llvm::toString(std::move(err)) << "\n";
-}
-
-RunInTerminalDebugAdapterCommChannel::RunInTerminalDebugAdapterCommChannel(
-    StringRef comm_file)
-    : m_io(comm_file, "runInTerminal launcher") {}
-
-// Can't use \a std::future<llvm::Error> because it doesn't compile on Windows
-std::future<lldb::SBError>
-RunInTerminalDebugAdapterCommChannel::NotifyDidAttach() {
-  return std::async(std::launch::async, [&]() {
-    lldb::SBError error;
-    if (llvm::Error err =
-            m_io.SendJSON(RunInTerminalMessageDidAttach().ToJSON()))
-      error.SetErrorString(llvm::toString(std::move(err)).c_str());
-    return error;
-  });
-}
-
-Expected<lldb::pid_t> RunInTerminalDebugAdapterCommChannel::GetLauncherPid() {
-  if (Expected<RunInTerminalMessageUP> message =
-          GetNextMessage(m_io, std::chrono::seconds(20))) {
-    if (message.get()->kind == eRunInTerminalMessageKindPID)
-      return message.get()->GetAsPidMessage()->pid;
-    return ToError(*message.get());
-  } else {
-    return message.takeError();
-  }
-}
-
-std::string RunInTerminalDebugAdapterCommChannel::GetLauncherError() {
-  // We know there's been an error, so a small timeout is enough.
-  if (Expected<RunInTerminalMessageUP> message =
-          GetNextMessage(m_io, std::chrono::seconds(1)))
-    return toString(ToError(*message.get()));
-  else
-    return toString(message.takeError());
-}
-
-Expected<std::shared_ptr<FifoFile>> CreateRunInTerminalCommFile() {
-  SmallString<256> comm_file;
-  if (std::error_code EC = sys::fs::getPotentiallyUniqueTempFileName(
-          "lldb-dap-run-in-terminal-comm", "", comm_file))
-    return createStringError(EC, "Error making unique file name for "
-                                 "runInTerminal communication files");
-
-  return CreateFifoFile(comm_file.str());
-}
-
-} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/RunInTerminal.h 
b/lldb/tools/lldb-dap/RunInTerminal.h
deleted file mode 100644
index 457850c8ea538..0000000000000
--- a/lldb/tools/lldb-dap/RunInTerminal.h
+++ /dev/null
@@ -1,131 +0,0 @@
-//===-- 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_DAP_RUNINTERMINAL_H
-#define LLDB_TOOLS_LLDB_DAP_RUNINTERMINAL_H
-
-#include "FifoFiles.h"
-#include "lldb/API/SBError.h"
-
-#include <future>
-#include <memory>
-#include <string>
-
-namespace lldb_dap {
-
-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 adapter 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 WaitUntilDebugAdapterAttaches(std::chrono::milliseconds timeout);
-
-  /// Notify the debug adapter 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 adapter 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();
-
-  /// 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 adapter with
-/// the runInTerminal launcher.
-llvm::Expected<std::shared_ptr<FifoFile>> CreateRunInTerminalCommFile();
-
-} // namespace lldb_dap
-
-#endif // LLDB_TOOLS_LLDB_DAP_RUNINTERMINAL_H
diff --git a/lldb/tools/lldb-dap/tool/lldb-dap.cpp 
b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
index 9b9de5e21a742..78241afe0d698 100644
--- a/lldb/tools/lldb-dap/tool/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
@@ -10,7 +10,6 @@
 #include "DAPLog.h"
 #include "EventHelper.h"
 #include "Handler/RequestHandler.h"
-#include "RunInTerminal.h"
 #include "Transport.h"
 #include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBStream.h"
@@ -162,7 +161,6 @@ static void PrintVersion() {
 // In case of errors launching the target, a suitable error message will be
 // emitted to the debug adapter.
 static llvm::Error LaunchRunInTerminalTarget(llvm::opt::Arg &target_arg,
-                                             llvm::StringRef comm_file,
                                              lldb::pid_t debugger_pid,
                                              char *argv[]) {
 #if defined(_WIN32)
@@ -170,37 +168,42 @@ static llvm::Error 
LaunchRunInTerminalTarget(llvm::opt::Arg &target_arg,
       "runInTerminal is only supported on POSIX systems");
 #else
 
-  // On Linux with the Yama security module enabled, a process can only attach
-  // to its descendants by default. In the runInTerminal case the target
-  // process is launched by the client so we need to allow tracing explicitly.
+  auto pid = fork();
+  if (pid < 0) {
+    return llvm::createStringError(
+        std::error_code(errno, std::generic_category()), "fork failed");
+  }
+  if (pid == 0) {
+    // On Linux with the Yama security module enabled, a process can only 
attach
+    // to its descendants by default. In the runInTerminal case the target
+    // process is launched by the client so we need to allow tracing 
explicitly.
 #if defined(__linux__)
-  if (debugger_pid != LLDB_INVALID_PROCESS_ID)
-    (void)prctl(PR_SET_PTRACER, debugger_pid, 0, 0, 0);
+    if (debugger_pid != LLDB_INVALID_PROCESS_ID)
+      (void)prctl(PR_SET_PTRACER, debugger_pid, 0, 0, 0);
 #endif
-
-  RunInTerminalLauncherCommChannel comm_channel(comm_file);
-  if (llvm::Error err = comm_channel.NotifyPid())
-    return err;
-
-  // We will wait to be attached with a timeout. We don't wait indefinitely
-  // using a signal to prevent being paused forever.
-
-  // This env var should be used only for tests.
-  const char *timeout_env_var = getenv("LLDB_DAP_RIT_TIMEOUT_IN_MS");
-  int timeout_in_ms =
-      timeout_env_var != nullptr ? atoi(timeout_env_var) : 20000;
-  if (llvm::Error err = comm_channel.WaitUntilDebugAdapterAttaches(
-          std::chrono::milliseconds(timeout_in_ms))) {
-    return err;
+    kill(debugger_pid, SIGUSR1);
+    raise(SIGSTOP);
+    const char *target = target_arg.getValue();
+    execvp(target, argv);
+    std::string error = std::strerror(errno);
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   std::move(error));
   }
-
-  const char *target = target_arg.getValue();
-  execvp(target, argv);
-
-  std::string error = std::strerror(errno);
-  comm_channel.NotifyError(error);
-  return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                 std::move(error));
+  if (pid > 0) {
+    // This env var should be used only for tests.
+    const char *timeout_env_var = getenv("LLDB_DAP_RIT_TIMEOUT_IN_MS");
+    int timeout_in_ms =
+        timeout_env_var != nullptr ? atoi(timeout_env_var) : 20000;
+    std::this_thread::sleep_for(std::chrono::milliseconds(timeout_in_ms));
+    // the child should have either continued or exited by now, kill it if not
+    if (waitpid(pid, nullptr, WNOHANG | WCONTINUED | WUNTRACED) == 0) {
+      kill(pid, SIGKILL);
+      return llvm::createStringError(
+          llvm::inconvertibleErrorCode(),
+          "runInTerminal target did not resume in time");
+    }
+  }
+  return llvm::Error::success();
 #endif
 }
 
@@ -407,17 +410,14 @@ int main(int argc, char *argv[]) {
   }
 
   if (llvm::opt::Arg *target_arg = input_args.getLastArg(OPT_launch_target)) {
-    if (llvm::opt::Arg *comm_file = input_args.getLastArg(OPT_comm_file)) {
+    if (llvm::opt::Arg *debugger_pid = 
input_args.getLastArg(OPT_debugger_pid)) {
       lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
-      llvm::opt::Arg *debugger_pid = input_args.getLastArg(OPT_debugger_pid);
-      if (debugger_pid) {
-        llvm::StringRef debugger_pid_value = debugger_pid->getValue();
-        if (debugger_pid_value.getAsInteger(10, pid)) {
-          llvm::errs() << "'" << debugger_pid_value
-                       << "' is not a valid "
-                          "PID\n";
-          return EXIT_FAILURE;
-        }
+      llvm::StringRef debugger_pid_value = debugger_pid->getValue();
+      if (debugger_pid_value.getAsInteger(10, pid)) {
+        llvm::errs() << "'" << debugger_pid_value
+                    << "' is not a valid "
+                        "PID\n";
+        return EXIT_FAILURE;
       }
       int target_args_pos = argc;
       for (int i = 0; i < argc; i++) {
@@ -426,14 +426,13 @@ int main(int argc, char *argv[]) {
           break;
         }
       }
-      if (llvm::Error err =
-              LaunchRunInTerminalTarget(*target_arg, comm_file->getValue(), 
pid,
-                                        argv + target_args_pos)) {
+      if (llvm::Error err = LaunchRunInTerminalTarget(*target_arg, pid,
+                                                      argv + target_args_pos)) 
{
         llvm::errs() << llvm::toString(std::move(err)) << '\n';
         return EXIT_FAILURE;
       }
     } else {
-      llvm::errs() << "\"--launch-target\" requires \"--comm-file\" to be "
+      llvm::errs() << "\"--launch-target\" requires \"--debugger-pid\" to be "
                       "specified\n";
       return EXIT_FAILURE;
     }

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to