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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "FifoFiles.h" 10 11 #if !defined(_WIN32) 12 #include <sys/stat.h> 13 #include <sys/types.h> 14 #include <unistd.h> 15 #endif 16 17 #include <chrono> 18 #include <fstream> 19 #include <future> 20 #include <optional> 21 #include <thread> 22 23 #include "llvm/Support/FileSystem.h" 24 25 #include "lldb/lldb-defines.h" 26 27 using namespace llvm; 28 29 namespace lldb_vscode { 30 31 FifoFile::FifoFile(StringRef path) : m_path(path) {} 32 33 FifoFile::~FifoFile() { 34 #if !defined(_WIN32) 35 unlink(m_path.c_str()); 36 #endif 37 } 38 39 Expected<std::shared_ptr<FifoFile>> CreateFifoFile(StringRef path) { 40 #if defined(_WIN32) 41 return createStringError(inconvertibleErrorCode(), "Unimplemented"); 42 #else 43 if (int err = mkfifo(path.data(), 0600)) 44 return createStringError(std::error_code(err, std::generic_category()), 45 "Couldn't create fifo file: %s", path.data()); 46 return std::make_shared<FifoFile>(path); 47 #endif 48 } 49 50 FifoFileIO::FifoFileIO(StringRef fifo_file, StringRef other_endpoint_name) 51 : m_fifo_file(fifo_file), m_other_endpoint_name(other_endpoint_name) {} 52 53 Expected<json::Value> FifoFileIO::ReadJSON(std::chrono::milliseconds timeout) { 54 // We use a pointer for this future, because otherwise its normal destructor 55 // would wait for the getline to end, rendering the timeout useless. 56 std::optional<std::string> line; 57 std::future<void> *future = 58 new std::future<void>(std::async(std::launch::async, [&]() { 59 std::ifstream reader(m_fifo_file, std::ifstream::in); 60 std::string buffer; 61 std::getline(reader, buffer); 62 if (!buffer.empty()) 63 line = buffer; 64 })); 65 if (future->wait_for(timeout) == std::future_status::timeout || !line) 66 // Indeed this is a leak, but it's intentional. "future" obj destructor 67 // will block on waiting for the worker thread to join. And the worker 68 // thread might be stuck in blocking I/O. Intentionally leaking the obj 69 // as a hack to avoid blocking main thread, and adding annotation to 70 // supress static code inspection warnings 71 72 // coverity[leaked_storage] 73 return createStringError(inconvertibleErrorCode(), 74 "Timed out trying to get messages from the " + 75 m_other_endpoint_name); 76 delete future; 77 return json::parse(*line); 78 } 79 80 Error FifoFileIO::SendJSON(const json::Value &json, 81 std::chrono::milliseconds timeout) { 82 bool done = false; 83 std::future<void> *future = 84 new std::future<void>(std::async(std::launch::async, [&]() { 85 std::ofstream writer(m_fifo_file, std::ofstream::out); 86 writer << JSONToString(json) << std::endl; 87 done = true; 88 })); 89 if (future->wait_for(timeout) == std::future_status::timeout || !done) { 90 // Indeed this is a leak, but it's intentional. "future" obj destructor will 91 // block on waiting for the worker thread to join. And the worker thread 92 // might be stuck in blocking I/O. Intentionally leaking the obj as a hack 93 // to avoid blocking main thread, and adding annotation to supress static 94 // code inspection warnings" 95 96 // coverity[leaked_storage] 97 return createStringError(inconvertibleErrorCode(), 98 "Timed out trying to send messages to the " + 99 m_other_endpoint_name); 100 } 101 delete future; 102 return Error::success(); 103 } 104 105 } // namespace lldb_vscode 106