[Lldb-commits] [lldb] 0a36c87 - [lldb][windows] add a Windows FifoFile implementation (#185894)

via lldb-commits lldb-commits at lists.llvm.org
Fri Mar 13 05:56:17 PDT 2026


Author: Charles Zablit
Date: 2026-03-13T12:56:11Z
New Revision: 0a36c87bc56fad72909f79e489f9109a96ebc3e2

URL: https://github.com/llvm/llvm-project/commit/0a36c87bc56fad72909f79e489f9109a96ebc3e2
DIFF: https://github.com/llvm/llvm-project/commit/0a36c87bc56fad72909f79e489f9109a96ebc3e2.diff

LOG: [lldb][windows] add a Windows FifoFile implementation (#185894)

This patch is a prelude to
https://github.com/llvm/llvm-project/pull/174635. It implements a
Windows version of the `FifoFile` class used in lldb-dap.

This change is not used as is, it will be used when
https://github.com/llvm/llvm-project/pull/174635 lands.

Added: 
    

Modified: 
    lldb/tools/lldb-dap/FifoFiles.cpp
    lldb/tools/lldb-dap/FifoFiles.h
    lldb/tools/lldb-dap/Handler/RequestHandler.cpp
    lldb/tools/lldb-dap/RunInTerminal.cpp
    lldb/tools/lldb-dap/RunInTerminal.h
    lldb/unittests/DAP/FifoFilesTest.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/tools/lldb-dap/FifoFiles.cpp b/lldb/tools/lldb-dap/FifoFiles.cpp
index 1f1bba80bd3b1..8f4485b921d94 100644
--- a/lldb/tools/lldb-dap/FifoFiles.cpp
+++ b/lldb/tools/lldb-dap/FifoFiles.cpp
@@ -9,7 +9,11 @@
 #include "FifoFiles.h"
 #include "JSONUtils.h"
 
-#if !defined(_WIN32)
+#ifdef _WIN32
+#include "lldb/Host/windows/PipeWindows.h"
+#include "lldb/Host/windows/windows.h"
+#include "llvm/Support/Path.h"
+#else
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -24,17 +28,88 @@ using namespace llvm;
 
 namespace lldb_dap {
 
-FifoFile::FifoFile(StringRef path) : m_path(path) {}
+FifoFile::FifoFile(StringRef path, lldb::pipe_t pipe) : m_path(path) {
+#ifdef _WIN32
+  if (pipe == INVALID_HANDLE_VALUE) {
+    assert(path.starts_with("\\\\.\\pipe\\") &&
+           "FifoFile path should start with '\\\\.\\pipe\\'");
+    pipe = CreateFileA(m_path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,
+                       OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+    DWORD mode = PIPE_READMODE_MESSAGE;
+    SetNamedPipeHandleState(pipe, &mode, NULL, NULL);
+  }
+#endif
+  m_pipe = pipe;
+}
 
 FifoFile::~FifoFile() {
-#if !defined(_WIN32)
+#ifdef _WIN32
+  if (m_pipe != INVALID_HANDLE_VALUE) {
+    DisconnectNamedPipe(m_pipe);
+    CloseHandle(m_pipe);
+  }
+#else
   unlink(m_path.c_str());
 #endif
 }
 
+void FifoFile::WriteLine(llvm::StringRef line) {
+#ifdef _WIN32
+  DWORD written;
+  std::string str = line.str() + "\n";
+  WriteFile(m_pipe, str.data(), static_cast<DWORD>(str.size()), &written, NULL);
+  FlushFileBuffers(m_pipe);
+#else
+  std::ofstream writer(m_path, std::ofstream::out);
+  writer << line.data() << std::endl;
+#endif
+}
+
+void FifoFile::Connect() {
+#ifdef _WIN32
+  ConnectNamedPipe(m_pipe, NULL);
+#endif
+}
+
+std::string FifoFile::ReadLine() {
+#ifdef _WIN32
+  std::string buffer;
+  char read_buffer[4096];
+  DWORD bytes_read;
+
+  while (true) {
+    BOOL success =
+        ReadFile(m_pipe, read_buffer, sizeof(read_buffer), &bytes_read, NULL);
+    buffer.append(read_buffer, bytes_read);
+    if (success || GetLastError() != ERROR_MORE_DATA)
+      break;
+  }
+
+  return buffer;
+#else
+  std::ifstream reader(m_path, std::ifstream::in);
+  std::string buffer;
+  std::getline(reader, buffer);
+  return buffer;
+#endif
+}
+
 Expected<std::shared_ptr<FifoFile>> CreateFifoFile(StringRef path) {
 #if defined(_WIN32)
-  return createStringError(inconvertibleErrorCode(), "Unimplemented");
+  assert(path.starts_with("\\\\.\\pipe\\") &&
+         "FifoFile path should start with '\\\\.\\pipe\\'");
+  HANDLE pipe_handle =
+      CreateNamedPipeA(path.data(), PIPE_ACCESS_DUPLEX,
+                       PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+                       PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, NULL);
+
+  if (pipe_handle == INVALID_HANDLE_VALUE) {
+    DWORD error = GetLastError();
+    return createStringError(std::error_code(error, std::system_category()),
+                             "Couldn't create named pipe: %s", path.data());
+  }
+
+  return std::make_shared<FifoFile>(path, pipe_handle);
 #else
   if (int err = mkfifo(path.data(), 0600))
     return createStringError(std::error_code(err, std::generic_category()),
@@ -43,8 +118,10 @@ Expected<std::shared_ptr<FifoFile>> CreateFifoFile(StringRef path) {
 #endif
 }
 
-FifoFileIO::FifoFileIO(StringRef fifo_file, StringRef other_endpoint_name)
-    : m_fifo_file(fifo_file), m_other_endpoint_name(other_endpoint_name) {}
+FifoFileIO::FifoFileIO(std::shared_ptr<FifoFile> fifo_file,
+                       StringRef other_endpoint_name)
+    : m_fifo_file(std::move(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
@@ -52,9 +129,7 @@ Expected<json::Value> FifoFileIO::ReadJSON(std::chrono::milliseconds timeout) {
   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);
+        std::string buffer = m_fifo_file->ReadLine();
         if (!buffer.empty())
           line = buffer;
       }));
@@ -78,8 +153,7 @@ Error FifoFileIO::SendJSON(const json::Value &json,
   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;
+        m_fifo_file->WriteLine(JSONToString(json));
         done = true;
       }));
   if (future->wait_for(timeout) == std::future_status::timeout || !done) {
@@ -98,4 +172,4 @@ Error FifoFileIO::SendJSON(const json::Value &json,
   return Error::success();
 }
 
-} // namespace lldb_dap
+} // namespace lldb_dap
\ No newline at end of file

diff  --git a/lldb/tools/lldb-dap/FifoFiles.h b/lldb/tools/lldb-dap/FifoFiles.h
index 633ebeb2aedd4..96e6b7f640e61 100644
--- a/lldb/tools/lldb-dap/FifoFiles.h
+++ b/lldb/tools/lldb-dap/FifoFiles.h
@@ -9,6 +9,7 @@
 #ifndef LLDB_TOOLS_LLDB_DAP_FIFOFILES_H
 #define LLDB_TOOLS_LLDB_DAP_FIFOFILES_H
 
+#include "lldb/Host/Pipe.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/JSON.h"
 
@@ -20,11 +21,27 @@ namespace lldb_dap {
 ///
 /// The file is destroyed when the destructor is invoked.
 struct FifoFile {
-  FifoFile(llvm::StringRef path);
+  FifoFile(llvm::StringRef path, lldb::pipe_t pipe = LLDB_INVALID_PIPE);
 
   ~FifoFile();
 
+  void Connect();
+
+  void WriteLine(llvm::StringRef line);
+
+  std::string ReadLine();
+
+  llvm::StringRef GetPath() { return m_path; }
+
+  /// FifoFile is not copyable.
+  /// @{
+  FifoFile(const FifoFile &rhs) = delete;
+  void operator=(const FifoFile &rhs) = delete;
+  /// @}
+
+protected:
   std::string m_path;
+  lldb::pipe_t m_pipe;
 };
 
 /// Create a fifo file in the filesystem.
@@ -45,7 +62,8 @@ class FifoFileIO {
   /// \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);
+  FifoFileIO(std::shared_ptr<FifoFile> fifo_file,
+             llvm::StringRef other_endpoint_name);
 
   /// Read the next JSON object from the underlying input fifo file.
   ///
@@ -76,7 +94,7 @@ class FifoFileIO {
       std::chrono::milliseconds timeout = std::chrono::milliseconds(20000));
 
 private:
-  std::string m_fifo_file;
+  std::shared_ptr<FifoFile> m_fifo_file;
   std::string m_other_endpoint_name;
 };
 

diff  --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
index 5e8c2163c838f..103d1f7beb873 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
@@ -103,9 +103,9 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) {
       CreateRunInTerminalCommFile();
   if (!comm_file_or_err)
     return comm_file_or_err.takeError();
-  FifoFile &comm_file = *comm_file_or_err.get();
+  std::shared_ptr<FifoFile> comm_file = *comm_file_or_err;
 
-  RunInTerminalDebugAdapterCommChannel comm_channel(comm_file.m_path);
+  RunInTerminalDebugAdapterCommChannel comm_channel(comm_file);
 
   lldb::pid_t debugger_pid = LLDB_INVALID_PROCESS_ID;
 #if !defined(_WIN32)
@@ -114,7 +114,7 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) {
 
   llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest(
       arguments.configuration.program, arguments.args, arguments.env,
-      arguments.cwd, comm_file.m_path, debugger_pid, arguments.stdio,
+      arguments.cwd, comm_file->GetPath(), debugger_pid, arguments.stdio,
       arguments.console == protocol::eConsoleExternalTerminal);
   dap.SendReverseRequest<LogFailureResponseHandler>("runInTerminal",
                                                     std::move(reverse_request));

diff  --git a/lldb/tools/lldb-dap/RunInTerminal.cpp b/lldb/tools/lldb-dap/RunInTerminal.cpp
index 9f309dd78221a..ccdad350cdef7 100644
--- a/lldb/tools/lldb-dap/RunInTerminal.cpp
+++ b/lldb/tools/lldb-dap/RunInTerminal.cpp
@@ -97,7 +97,7 @@ static Error ToError(const RunInTerminalMessage &message) {
 
 RunInTerminalLauncherCommChannel::RunInTerminalLauncherCommChannel(
     StringRef comm_file)
-    : m_io(comm_file, "debug adapter") {}
+    : m_io(std::make_shared<FifoFile>(comm_file), "debug adapter") {}
 
 Error RunInTerminalLauncherCommChannel::WaitUntilDebugAdapterAttaches(
     std::chrono::milliseconds timeout) {
@@ -123,7 +123,11 @@ void RunInTerminalLauncherCommChannel::NotifyError(StringRef error) {
 
 RunInTerminalDebugAdapterCommChannel::RunInTerminalDebugAdapterCommChannel(
     StringRef comm_file)
-    : m_io(comm_file, "runInTerminal launcher") {}
+    : m_io(std::make_shared<FifoFile>(comm_file), "runInTerminal launcher") {}
+
+RunInTerminalDebugAdapterCommChannel::RunInTerminalDebugAdapterCommChannel(
+    std::shared_ptr<FifoFile> comm_file)
+    : m_io(std::move(comm_file), "runInTerminal launcher") {}
 
 // Can't use \a std::future<llvm::Error> because it doesn't compile on Windows
 std::future<lldb::SBError>

diff  --git a/lldb/tools/lldb-dap/RunInTerminal.h b/lldb/tools/lldb-dap/RunInTerminal.h
index 457850c8ea538..f6e922e59a095 100644
--- a/lldb/tools/lldb-dap/RunInTerminal.h
+++ b/lldb/tools/lldb-dap/RunInTerminal.h
@@ -99,6 +99,7 @@ class RunInTerminalLauncherCommChannel {
 class RunInTerminalDebugAdapterCommChannel {
 public:
   RunInTerminalDebugAdapterCommChannel(llvm::StringRef comm_file);
+  RunInTerminalDebugAdapterCommChannel(std::shared_ptr<FifoFile> comm_file);
 
   /// Notify the runInTerminal launcher that it was attached.
   ///

diff  --git a/lldb/unittests/DAP/FifoFilesTest.cpp b/lldb/unittests/DAP/FifoFilesTest.cpp
index bbc1b608e91bd..e59fc54cc9543 100644
--- a/lldb/unittests/DAP/FifoFilesTest.cpp
+++ b/lldb/unittests/DAP/FifoFilesTest.cpp
@@ -45,8 +45,8 @@ TEST(FifoFilesTest, SendAndReceiveJSON) {
   auto fifo = CreateFifoFile(fifo_path);
   EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded());
 
-  FifoFileIO writer(fifo_path, "writer");
-  FifoFileIO reader(fifo_path, "reader");
+  FifoFileIO writer(*fifo, "writer");
+  FifoFileIO reader(*fifo, "reader");
 
   llvm::json::Object obj;
   obj["foo"] = "bar";
@@ -79,7 +79,7 @@ TEST(FifoFilesTest, ReadTimeout) {
   auto fifo = CreateFifoFile(fifo_path);
   EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded());
 
-  FifoFileIO reader(fifo_path, "reader");
+  FifoFileIO reader(*fifo, "reader");
 
   // No writer, should timeout.
   auto result = reader.ReadJSON(std::chrono::milliseconds(100));
@@ -91,7 +91,7 @@ TEST(FifoFilesTest, WriteTimeout) {
   auto fifo = CreateFifoFile(fifo_path);
   EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded());
 
-  FifoFileIO writer(fifo_path, "writer");
+  FifoFileIO writer(*fifo, "writer");
 
   // No reader, should timeout.
   llvm::json::Object obj;


        


More information about the lldb-commits mailing list