102 lines · cpp
1//===-- FifoFiles.cpp -------------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "FifoFiles.h"10#include "JSONUtils.h"11 12#if !defined(_WIN32)13#include <sys/stat.h>14#include <sys/types.h>15#include <unistd.h>16#endif17 18#include <chrono>19#include <fstream>20#include <future>21#include <optional>22 23using namespace llvm;24 25namespace lldb_dap {26 27FifoFile::FifoFile(StringRef path) : m_path(path) {}28 29FifoFile::~FifoFile() {30#if !defined(_WIN32)31 unlink(m_path.c_str());32#endif33}34 35Expected<std::shared_ptr<FifoFile>> CreateFifoFile(StringRef path) {36#if defined(_WIN32)37 return createStringError(inconvertibleErrorCode(), "Unimplemented");38#else39 if (int err = mkfifo(path.data(), 0600))40 return createStringError(std::error_code(err, std::generic_category()),41 "Couldn't create fifo file: %s", path.data());42 return std::make_shared<FifoFile>(path);43#endif44}45 46FifoFileIO::FifoFileIO(StringRef fifo_file, StringRef other_endpoint_name)47 : m_fifo_file(fifo_file), m_other_endpoint_name(other_endpoint_name) {}48 49Expected<json::Value> FifoFileIO::ReadJSON(std::chrono::milliseconds timeout) {50 // We use a pointer for this future, because otherwise its normal destructor51 // would wait for the getline to end, rendering the timeout useless.52 std::optional<std::string> line;53 std::future<void> *future =54 new std::future<void>(std::async(std::launch::async, [&]() {55 std::ifstream reader(m_fifo_file, std::ifstream::in);56 std::string buffer;57 std::getline(reader, buffer);58 if (!buffer.empty())59 line = buffer;60 }));61 if (future->wait_for(timeout) == std::future_status::timeout || !line)62 // Indeed this is a leak, but it's intentional. "future" obj destructor63 // will block on waiting for the worker thread to join. And the worker64 // thread might be stuck in blocking I/O. Intentionally leaking the obj65 // as a hack to avoid blocking main thread, and adding annotation to66 // supress static code inspection warnings67 68 // coverity[leaked_storage]69 return createStringError(inconvertibleErrorCode(),70 "Timed out trying to get messages from the " +71 m_other_endpoint_name);72 delete future;73 return json::parse(*line);74}75 76Error FifoFileIO::SendJSON(const json::Value &json,77 std::chrono::milliseconds timeout) {78 bool done = false;79 std::future<void> *future =80 new std::future<void>(std::async(std::launch::async, [&]() {81 std::ofstream writer(m_fifo_file, std::ofstream::out);82 writer << JSONToString(json) << std::endl;83 done = true;84 }));85 if (future->wait_for(timeout) == std::future_status::timeout || !done) {86 // Indeed this is a leak, but it's intentional. "future" obj destructor will87 // block on waiting for the worker thread to join. And the worker thread88 // might be stuck in blocking I/O. Intentionally leaking the obj as a hack89 // to avoid blocking main thread, and adding annotation to supress static90 // code inspection warnings"91 92 // coverity[leaked_storage]93 return createStringError(inconvertibleErrorCode(),94 "Timed out trying to send messages to the " +95 m_other_endpoint_name);96 }97 delete future;98 return Error::success();99}100 101} // namespace lldb_dap102