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