xref: /llvm-project/lldb/tools/lldb-vscode/FifoFiles.cpp (revision 09c258ef6a2fcca2161488b214d53ef39891fa22)
101263c6cSJonas Devlieghere //===-- FifoFiles.cpp -------------------------------------------*- C++ -*-===//
201263c6cSJonas Devlieghere //
301263c6cSJonas Devlieghere // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
401263c6cSJonas Devlieghere // See https://llvm.org/LICENSE.txt for license information.
501263c6cSJonas Devlieghere // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
601263c6cSJonas Devlieghere //
701263c6cSJonas Devlieghere //===----------------------------------------------------------------------===//
801263c6cSJonas Devlieghere 
901263c6cSJonas Devlieghere #include "FifoFiles.h"
10*09c258efSAdrian Vogelsgesang #include "JSONUtils.h"
1101263c6cSJonas Devlieghere 
1201263c6cSJonas Devlieghere #if !defined(_WIN32)
1301263c6cSJonas Devlieghere #include <sys/stat.h>
1401263c6cSJonas Devlieghere #include <sys/types.h>
1501263c6cSJonas Devlieghere #include <unistd.h>
1601263c6cSJonas Devlieghere #endif
1701263c6cSJonas Devlieghere 
1801263c6cSJonas Devlieghere #include <chrono>
1901263c6cSJonas Devlieghere #include <fstream>
2001263c6cSJonas Devlieghere #include <future>
2101263c6cSJonas Devlieghere #include <optional>
2201263c6cSJonas Devlieghere 
2301263c6cSJonas Devlieghere using namespace llvm;
2401263c6cSJonas Devlieghere 
2501263c6cSJonas Devlieghere namespace lldb_dap {
2601263c6cSJonas Devlieghere 
2701263c6cSJonas Devlieghere FifoFile::FifoFile(StringRef path) : m_path(path) {}
2801263c6cSJonas Devlieghere 
2901263c6cSJonas Devlieghere FifoFile::~FifoFile() {
3001263c6cSJonas Devlieghere #if !defined(_WIN32)
3101263c6cSJonas Devlieghere   unlink(m_path.c_str());
3201263c6cSJonas Devlieghere #endif
3301263c6cSJonas Devlieghere }
3401263c6cSJonas Devlieghere 
3501263c6cSJonas Devlieghere Expected<std::shared_ptr<FifoFile>> CreateFifoFile(StringRef path) {
3601263c6cSJonas Devlieghere #if defined(_WIN32)
3701263c6cSJonas Devlieghere   return createStringError(inconvertibleErrorCode(), "Unimplemented");
3801263c6cSJonas Devlieghere #else
3901263c6cSJonas Devlieghere   if (int err = mkfifo(path.data(), 0600))
4001263c6cSJonas Devlieghere     return createStringError(std::error_code(err, std::generic_category()),
4101263c6cSJonas Devlieghere                              "Couldn't create fifo file: %s", path.data());
4201263c6cSJonas Devlieghere   return std::make_shared<FifoFile>(path);
4301263c6cSJonas Devlieghere #endif
4401263c6cSJonas Devlieghere }
4501263c6cSJonas Devlieghere 
4601263c6cSJonas Devlieghere FifoFileIO::FifoFileIO(StringRef fifo_file, StringRef other_endpoint_name)
4701263c6cSJonas Devlieghere     : m_fifo_file(fifo_file), m_other_endpoint_name(other_endpoint_name) {}
4801263c6cSJonas Devlieghere 
4901263c6cSJonas Devlieghere Expected<json::Value> FifoFileIO::ReadJSON(std::chrono::milliseconds timeout) {
5001263c6cSJonas Devlieghere   // We use a pointer for this future, because otherwise its normal destructor
5101263c6cSJonas Devlieghere   // would wait for the getline to end, rendering the timeout useless.
5201263c6cSJonas Devlieghere   std::optional<std::string> line;
5301263c6cSJonas Devlieghere   std::future<void> *future =
5401263c6cSJonas Devlieghere       new std::future<void>(std::async(std::launch::async, [&]() {
5501263c6cSJonas Devlieghere         std::ifstream reader(m_fifo_file, std::ifstream::in);
5601263c6cSJonas Devlieghere         std::string buffer;
5701263c6cSJonas Devlieghere         std::getline(reader, buffer);
5801263c6cSJonas Devlieghere         if (!buffer.empty())
5901263c6cSJonas Devlieghere           line = buffer;
6001263c6cSJonas Devlieghere       }));
6101263c6cSJonas Devlieghere   if (future->wait_for(timeout) == std::future_status::timeout || !line)
6201263c6cSJonas Devlieghere     // Indeed this is a leak, but it's intentional. "future" obj destructor
6301263c6cSJonas Devlieghere     //  will block on waiting for the worker thread to join. And the worker
6401263c6cSJonas Devlieghere     //  thread might be stuck in blocking I/O. Intentionally leaking the  obj
6501263c6cSJonas Devlieghere     //  as a hack to avoid blocking main thread, and adding annotation to
6601263c6cSJonas Devlieghere     //  supress static code inspection warnings
6701263c6cSJonas Devlieghere 
6801263c6cSJonas Devlieghere     // coverity[leaked_storage]
6901263c6cSJonas Devlieghere     return createStringError(inconvertibleErrorCode(),
7001263c6cSJonas Devlieghere                              "Timed out trying to get messages from the " +
7101263c6cSJonas Devlieghere                                  m_other_endpoint_name);
7201263c6cSJonas Devlieghere   delete future;
7301263c6cSJonas Devlieghere   return json::parse(*line);
7401263c6cSJonas Devlieghere }
7501263c6cSJonas Devlieghere 
7601263c6cSJonas Devlieghere Error FifoFileIO::SendJSON(const json::Value &json,
7701263c6cSJonas Devlieghere                            std::chrono::milliseconds timeout) {
7801263c6cSJonas Devlieghere   bool done = false;
7901263c6cSJonas Devlieghere   std::future<void> *future =
8001263c6cSJonas Devlieghere       new std::future<void>(std::async(std::launch::async, [&]() {
8101263c6cSJonas Devlieghere         std::ofstream writer(m_fifo_file, std::ofstream::out);
8201263c6cSJonas Devlieghere         writer << JSONToString(json) << std::endl;
8301263c6cSJonas Devlieghere         done = true;
8401263c6cSJonas Devlieghere       }));
8501263c6cSJonas Devlieghere   if (future->wait_for(timeout) == std::future_status::timeout || !done) {
8601263c6cSJonas Devlieghere     // Indeed this is a leak, but it's intentional. "future" obj destructor will
8701263c6cSJonas Devlieghere     // block on waiting for the worker thread to join. And the worker thread
8801263c6cSJonas Devlieghere     // might be stuck in blocking I/O. Intentionally leaking the  obj as a hack
8901263c6cSJonas Devlieghere     // to avoid blocking main thread, and adding annotation to supress static
9001263c6cSJonas Devlieghere     // code inspection warnings"
9101263c6cSJonas Devlieghere 
9201263c6cSJonas Devlieghere     // coverity[leaked_storage]
9301263c6cSJonas Devlieghere     return createStringError(inconvertibleErrorCode(),
9401263c6cSJonas Devlieghere                              "Timed out trying to send messages to the " +
9501263c6cSJonas Devlieghere                                  m_other_endpoint_name);
9601263c6cSJonas Devlieghere   }
9701263c6cSJonas Devlieghere   delete future;
9801263c6cSJonas Devlieghere   return Error::success();
9901263c6cSJonas Devlieghere }
10001263c6cSJonas Devlieghere 
10101263c6cSJonas Devlieghere } // namespace lldb_dap
102