diff --git a/lldb/tools/lldb-vscode/lldb-vscode.cpp b/lldb/tools/lldb-vscode/lldb-vscode.cpp --- a/lldb/tools/lldb-vscode/lldb-vscode.cpp +++ b/lldb/tools/lldb-vscode/lldb-vscode.cpp @@ -3145,6 +3145,93 @@ return new_stdout_fd; } +class RequestQueue { +public: + RequestQueue() = default; + + RequestQueue(const RequestQueue &) = delete ; + RequestQueue& operator=(const RequestQueue &) = delete; + + /// Get the next front element from the queue or \a None if + /// the queue has been terminated. + llvm::Optional Pop() { + std::unique_lock lock(m_mutex); + while(m_data.empty() && !m_termination_status) + m_can_consume.wait(lock); + + if (m_termination_status) + return llvm::None; + + llvm::json::Object request(std::move(m_data.front())); + m_data.pop_front(); + return std::move(request); + } + + /// Push a new element in the queue, unless it has been terminated. + void Push(llvm::json::Object &&obj) { + std::lock_guard lock(m_mutex); + if (m_termination_status) + return; + + bool was_empty = m_data.empty(); + m_data.emplace_back(std::move(obj)); + if (was_empty) + m_can_consume.notify_one(); + } + + /// Terminate the queue. It won't accept more requests not provide more elements to the reader. + void Terminate(bool success) { + std::lock_guard lock(m_mutex); + + if (!m_termination_status) + m_termination_status = success; + m_can_consume.notify_one(); + } + + bool GetTerminationStatus() { + return *m_termination_status; + } + +private: + std::list m_data; + std::mutex m_mutex; + std::condition_variable m_can_consume; + llvm::Optional m_termination_status; +}; + +int StartReceivingPackets() { + RequestQueue requests; + + std::thread reader_thread ([&]{ + uint32_t packet_idx = 0; + while (!g_vsc.sent_terminated_event) { + llvm::json::Object object; + lldb_vscode::PacketStatus status = g_vsc.GetNextObject(object); + if (status == lldb_vscode::PacketStatus::EndOfFile) + break; + if (status != lldb_vscode::PacketStatus::Success) { + requests.Terminate(false); + break; + } + + requests.Push(std::move(object)); + ++packet_idx; + } + requests.Terminate(true); + }); + + std::thread worker_thread([&]() { + while (llvm::Optional object = requests.Pop()) { + if (!g_vsc.HandleObject(*object)) + requests.Terminate(false); + } + }); + reader_thread.join(); + worker_thread.join(); + + return requests.GetTerminationStatus() ? EXIT_SUCCESS : EXIT_FAILURE; +} + int main(int argc, char *argv[]) { llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false); llvm::PrettyStackTraceProgram X(argc, argv); @@ -3224,19 +3311,5 @@ g_vsc.output.descriptor = StreamDescriptor::from_file(new_stdout_fd, false); } - uint32_t packet_idx = 0; - while (!g_vsc.sent_terminated_event) { - llvm::json::Object object; - lldb_vscode::PacketStatus status = g_vsc.GetNextObject(object); - if (status == lldb_vscode::PacketStatus::EndOfFile) - break; - if (status != lldb_vscode::PacketStatus::Success) - return 1; // Fatal error - - if (!g_vsc.HandleObject(object)) - return 1; - ++packet_idx; - } - - return EXIT_SUCCESS; + return StartReceivingPackets(); }