Fix deadlock closing socket on another thread
while another thread is stuck in read() or write(). Fixes: #37
This commit is contained in:
parent
9003ee55b9
commit
2f607e077a
@ -169,20 +169,20 @@ class dap::Socket::Shared : public dap::ReaderWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void close() {
|
void close() {
|
||||||
#if !defined(_WIN32)
|
|
||||||
{
|
{
|
||||||
RLock l(mutex);
|
RLock l(mutex);
|
||||||
if (s != InvalidSocket) {
|
if (s != InvalidSocket) {
|
||||||
::shutdown(s, SHUT_RDWR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
WLock l(mutex);
|
|
||||||
if (s != InvalidSocket) {
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
closesocket(s);
|
closesocket(s);
|
||||||
#else
|
#else
|
||||||
|
::shutdown(s, SHUT_RDWR);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WLock l(mutex);
|
||||||
|
if (s != InvalidSocket) {
|
||||||
|
#if !defined(_WIN32)
|
||||||
::close(s);
|
::close(s);
|
||||||
#endif
|
#endif
|
||||||
s = InvalidSocket;
|
s = InvalidSocket;
|
||||||
|
@ -18,8 +18,61 @@
|
|||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
// Basic socket send & receive test
|
||||||
|
TEST(Socket, SendRecv) {
|
||||||
|
const char* port = "19021";
|
||||||
|
|
||||||
|
auto server = dap::Socket("localhost", port);
|
||||||
|
|
||||||
|
auto client = dap::Socket::connect("localhost", port, 0);
|
||||||
|
ASSERT_TRUE(client != nullptr);
|
||||||
|
|
||||||
|
const std::string expect = "Hello World!";
|
||||||
|
std::string read;
|
||||||
|
|
||||||
|
auto thread = std::thread([&] {
|
||||||
|
auto conn = server.accept();
|
||||||
|
ASSERT_TRUE(conn != nullptr);
|
||||||
|
char c;
|
||||||
|
while (conn->read(&c, 1) != 0) {
|
||||||
|
read += c;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_TRUE(client->write(expect.data(), expect.size()));
|
||||||
|
|
||||||
|
client->close();
|
||||||
|
thread.join();
|
||||||
|
|
||||||
|
ASSERT_EQ(read, expect);
|
||||||
|
}
|
||||||
|
|
||||||
|
// See https://github.com/google/cppdap/issues/37
|
||||||
|
TEST(Socket, CloseOnDifferentThread) {
|
||||||
|
const char* port = "19021";
|
||||||
|
|
||||||
|
auto server = dap::Socket("localhost", port);
|
||||||
|
|
||||||
|
auto client = dap::Socket::connect("localhost", port, 0);
|
||||||
|
ASSERT_TRUE(client != nullptr);
|
||||||
|
|
||||||
|
auto conn = server.accept();
|
||||||
|
|
||||||
|
auto thread = std::thread([&] {
|
||||||
|
// Closing client on different thread should unblock client->read().
|
||||||
|
client->close();
|
||||||
|
});
|
||||||
|
|
||||||
|
char c;
|
||||||
|
while (client->read(&c, 1) != 0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
TEST(Socket, ConnectTimeout) {
|
TEST(Socket, ConnectTimeout) {
|
||||||
const char* port = "19021";
|
const char* port = "19021";
|
||||||
const int timeoutMillis = 200;
|
const int timeoutMillis = 200;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user