Add Session::ClosedHandler (#99)

A callback function to signal that the endpoint has closed its connection.

Add this as an optional argument to Session::bind() and Session::startProcessingMessages().

Bug: #98
This commit is contained in:
Ben Clayton
2023-02-28 14:26:12 +00:00
committed by GitHub
parent 315ffff9e7
commit 59819690ec
3 changed files with 84 additions and 19 deletions

View File

@@ -65,7 +65,7 @@ class Impl : public dap::Session {
void connect(const std::shared_ptr<dap::Reader>& r,
const std::shared_ptr<dap::Writer>& w) override {
if (isBound.exchange(true)) {
handlers.error("Session is already bound!");
handlers.error("Session::connect called twice");
return;
}
@@ -73,13 +73,21 @@ class Impl : public dap::Session {
writer = dap::ContentWriter(w);
}
void startProcessingMessages() override {
recvThread = std::thread([this] {
void startProcessingMessages(
const ClosedHandler& onClose /* = {} */) override {
if (isProcessingMessages.exchange(true)) {
handlers.error("Session::startProcessingMessages() called twice");
return;
}
recvThread = std::thread([this, onClose] {
while (reader.isOpen()) {
if (auto payload = getPayload()) {
inbox.put(std::move(payload));
}
}
if (onClose) {
onClose();
}
});
dispatchThread = std::thread([this] {
@@ -398,17 +406,17 @@ class Impl : public dap::Session {
// "body" is an optional field for some events, such as "Terminated Event".
bool body_ok = true;
d->field("body", [&](dap::Deserializer* d) {
if (!typeinfo->deserialize(d, data)) {
body_ok = false;
}
return true;
if (!typeinfo->deserialize(d, data)) {
body_ok = false;
}
return true;
});
if (!body_ok) {
handlers.error("Failed to deserialize event '%s' body", event.c_str());
typeinfo->destruct(data);
delete[] data;
return {};
handlers.error("Failed to deserialize event '%s' body", event.c_str());
typeinfo->destruct(data);
delete[] data;
return {};
}
return [=] {
@@ -471,6 +479,7 @@ class Impl : public dap::Session {
}
std::atomic<bool> isBound = {false};
std::atomic<bool> isProcessingMessages = {false};
dap::ContentReader reader;
dap::ContentWriter writer;

View File

@@ -579,3 +579,47 @@ TEST_F(SessionTest, Concurrency) {
client.reset();
server.reset();
}
TEST_F(SessionTest, OnClientClosed) {
std::mutex mutex;
std::condition_variable cv;
bool clientClosed = false;
auto client2server = dap::pipe();
auto server2client = dap::pipe();
client->bind(server2client, client2server);
server->bind(client2server, server2client, [&] {
std::unique_lock<std::mutex> lock(mutex);
clientClosed = true;
cv.notify_all();
});
client.reset();
// Wait for the client closed handler to be called.
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock, [&] { return static_cast<bool>(clientClosed); });
}
TEST_F(SessionTest, OnServerClosed) {
std::mutex mutex;
std::condition_variable cv;
bool serverClosed = false;
auto client2server = dap::pipe();
auto server2client = dap::pipe();
client->bind(server2client, client2server, [&] {
std::unique_lock<std::mutex> lock(mutex);
serverClosed = true;
cv.notify_all();
});
server->bind(client2server, server2client);
server.reset();
// Wait for the client closed handler to be called.
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock, [&] { return static_cast<bool>(serverClosed); });
}