1*be691f3bSpatrick //===-- FifoFiles.cpp -------------------------------------------*- C++ -*-===// 2*be691f3bSpatrick // 3*be691f3bSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*be691f3bSpatrick // See https://llvm.org/LICENSE.txt for license information. 5*be691f3bSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*be691f3bSpatrick // 7*be691f3bSpatrick //===----------------------------------------------------------------------===// 8*be691f3bSpatrick 9*be691f3bSpatrick #include "FifoFiles.h" 10*be691f3bSpatrick 11*be691f3bSpatrick #if !defined(_WIN32) 12*be691f3bSpatrick #include <sys/stat.h> 13*be691f3bSpatrick #include <sys/types.h> 14*be691f3bSpatrick #include <unistd.h> 15*be691f3bSpatrick #endif 16*be691f3bSpatrick 17*be691f3bSpatrick #include <chrono> 18*be691f3bSpatrick #include <fstream> 19*be691f3bSpatrick #include <future> 20*be691f3bSpatrick #include <thread> 21*be691f3bSpatrick 22*be691f3bSpatrick #include "llvm/Support/FileSystem.h" 23*be691f3bSpatrick 24*be691f3bSpatrick #include "lldb/lldb-defines.h" 25*be691f3bSpatrick 26*be691f3bSpatrick using namespace llvm; 27*be691f3bSpatrick 28*be691f3bSpatrick namespace lldb_vscode { 29*be691f3bSpatrick 30*be691f3bSpatrick FifoFile::FifoFile(StringRef path) : m_path(path) {} 31*be691f3bSpatrick 32*be691f3bSpatrick FifoFile::~FifoFile() { 33*be691f3bSpatrick #if !defined(_WIN32) 34*be691f3bSpatrick unlink(m_path.c_str()); 35*be691f3bSpatrick #endif 36*be691f3bSpatrick } 37*be691f3bSpatrick 38*be691f3bSpatrick Expected<std::shared_ptr<FifoFile>> CreateFifoFile(StringRef path) { 39*be691f3bSpatrick #if defined(_WIN32) 40*be691f3bSpatrick return createStringError(inconvertibleErrorCode(), "Unimplemented"); 41*be691f3bSpatrick #else 42*be691f3bSpatrick if (int err = mkfifo(path.data(), 0600)) 43*be691f3bSpatrick return createStringError(std::error_code(err, std::generic_category()), 44*be691f3bSpatrick "Couldn't create fifo file: %s", path.data()); 45*be691f3bSpatrick return std::make_shared<FifoFile>(path); 46*be691f3bSpatrick #endif 47*be691f3bSpatrick } 48*be691f3bSpatrick 49*be691f3bSpatrick FifoFileIO::FifoFileIO(StringRef fifo_file, StringRef other_endpoint_name) 50*be691f3bSpatrick : m_fifo_file(fifo_file), m_other_endpoint_name(other_endpoint_name) {} 51*be691f3bSpatrick 52*be691f3bSpatrick Expected<json::Value> FifoFileIO::ReadJSON(std::chrono::milliseconds timeout) { 53*be691f3bSpatrick // We use a pointer for this future, because otherwise its normal destructor 54*be691f3bSpatrick // would wait for the getline to end, rendering the timeout useless. 55*be691f3bSpatrick Optional<std::string> line; 56*be691f3bSpatrick std::future<void> *future = 57*be691f3bSpatrick new std::future<void>(std::async(std::launch::async, [&]() { 58*be691f3bSpatrick std::ifstream reader(m_fifo_file, std::ifstream::in); 59*be691f3bSpatrick std::string buffer; 60*be691f3bSpatrick std::getline(reader, buffer); 61*be691f3bSpatrick if (!buffer.empty()) 62*be691f3bSpatrick line = buffer; 63*be691f3bSpatrick })); 64*be691f3bSpatrick if (future->wait_for(timeout) == std::future_status::timeout || 65*be691f3bSpatrick !line.hasValue()) 66*be691f3bSpatrick return createStringError(inconvertibleErrorCode(), 67*be691f3bSpatrick "Timed out trying to get messages from the " + 68*be691f3bSpatrick m_other_endpoint_name); 69*be691f3bSpatrick delete future; 70*be691f3bSpatrick return json::parse(*line); 71*be691f3bSpatrick } 72*be691f3bSpatrick 73*be691f3bSpatrick Error FifoFileIO::SendJSON(const json::Value &json, 74*be691f3bSpatrick std::chrono::milliseconds timeout) { 75*be691f3bSpatrick bool done = false; 76*be691f3bSpatrick std::future<void> *future = 77*be691f3bSpatrick new std::future<void>(std::async(std::launch::async, [&]() { 78*be691f3bSpatrick std::ofstream writer(m_fifo_file, std::ofstream::out); 79*be691f3bSpatrick writer << JSONToString(json) << std::endl; 80*be691f3bSpatrick done = true; 81*be691f3bSpatrick })); 82*be691f3bSpatrick if (future->wait_for(timeout) == std::future_status::timeout || !done) { 83*be691f3bSpatrick return createStringError(inconvertibleErrorCode(), 84*be691f3bSpatrick "Timed out trying to send messages to the " + 85*be691f3bSpatrick m_other_endpoint_name); 86*be691f3bSpatrick } 87*be691f3bSpatrick delete future; 88*be691f3bSpatrick return Error::success(); 89*be691f3bSpatrick } 90*be691f3bSpatrick 91*be691f3bSpatrick } // namespace lldb_vscode 92