blob: 0991ff7c17b7da04b42ecfd28144408fadc27de0 [file] [log] [blame]
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
#include "cmConfigure.h" // IWYU pragma: keep
#include <condition_variable>
#include <cstddef>
#include <future>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <cm3p/cppdap/io.h>
#include <cm3p/uv.h>
#include "cmDebuggerAdapter.h"
#include "cmUVHandlePtr.h"
namespace cmDebugger {
class cmDebuggerPipeBase : public dap::ReaderWriter
{
public:
cmDebuggerPipeBase(std::string name);
void WaitForConnection();
// dap::ReaderWriter implementation
void close() final;
size_t read(void* buffer, size_t n) final;
bool write(const void* buffer, size_t n) final;
protected:
virtual void CloseConnection(){};
template <typename T>
void StartReading(uv_stream_t* stream)
{
uv_read_start(
stream,
// alloc_cb
[](uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
(void)handle;
char* rawBuffer = new char[suggested_size];
*buf =
uv_buf_init(rawBuffer, static_cast<unsigned int>(suggested_size));
},
// read_cb
[](uv_stream_t* readStream, ssize_t nread, const uv_buf_t* buf) {
auto conn = static_cast<T*>(readStream->data);
if (conn) {
if (nread >= 0) {
conn->BufferData(std::string(buf->base, buf->base + nread));
} else {
conn->close();
}
}
delete[] (buf->base);
});
}
void StopLoop();
const std::string PipeName;
std::thread LoopThread;
cm::uv_loop_ptr Loop;
cm::uv_pipe_ptr Pipe;
std::mutex Mutex;
std::condition_variable Connected;
bool FailedToOpen = false;
private:
void BufferData(const std::string& data);
void WriteInternal();
cm::uv_async_ptr LoopExit;
cm::uv_async_ptr WriteEvent;
cm::uv_async_ptr PipeClose;
std::string WriteBuffer;
std::string ReadBuffer;
std::condition_variable ReadReady;
std::condition_variable WriteComplete;
};
class cmDebuggerPipeConnection
: public cmDebuggerPipeBase
, public cmDebuggerConnection
, public std::enable_shared_from_this<cmDebuggerPipeConnection>
{
public:
cmDebuggerPipeConnection(std::string name);
~cmDebuggerPipeConnection() override;
void WaitForConnection() override
{
cmDebuggerPipeBase::WaitForConnection();
}
bool StartListening(std::string& errorMessage) override;
std::shared_ptr<dap::Reader> GetReader() override;
std::shared_ptr<dap::Writer> GetWriter() override;
// dap::ReaderWriter implementation
bool isOpen() override;
// Used for unit test synchronization
std::promise<void> StartedListening;
private:
void CloseConnection() override;
void Connect(uv_stream_t* server);
cm::uv_pipe_ptr ServerPipe;
cm::uv_async_ptr ServerPipeClose;
};
class cmDebuggerPipeClient : public cmDebuggerPipeBase
{
public:
using cmDebuggerPipeBase::cmDebuggerPipeBase;
~cmDebuggerPipeClient() override;
void Start();
// dap::ReaderWriter implementation
bool isOpen() override;
private:
void CloseConnection() override;
void Connect();
void FailConnection();
bool IsConnected = false;
};
} // namespace cmDebugger