mirror of
https://github.com/pocoproject/poco.git
synced 2025-11-01 21:13:10 +01:00
fix(SocketReactor): Protect stop() and wakeUp() from reentrance #4217
This commit is contained in:
@@ -160,13 +160,14 @@ void SocketReactor::sleep()
|
||||
|
||||
void SocketReactor::stop()
|
||||
{
|
||||
_stop = true;
|
||||
if (_stop.exchange(true)) return;
|
||||
wakeUp();
|
||||
}
|
||||
|
||||
|
||||
void SocketReactor::wakeUp()
|
||||
{
|
||||
if (_stop) return;
|
||||
_pollSet.wakeUp();
|
||||
_event.set();
|
||||
}
|
||||
|
||||
@@ -395,6 +395,45 @@ namespace
|
||||
Poco::Thread::sleep(500);
|
||||
}
|
||||
};
|
||||
|
||||
class DummyServiceHandler
|
||||
{
|
||||
public:
|
||||
DummyServiceHandler(StreamSocket& socket, SocketReactor& reactor) : _socket(socket),
|
||||
_reactor(reactor)
|
||||
{
|
||||
_reactor.addEventHandler(_socket, Observer<DummyServiceHandler, ReadableNotification>(*this, &DummyServiceHandler::onReadable));
|
||||
_reactor.addEventHandler(_socket, Observer<DummyServiceHandler, ShutdownNotification>(*this, &DummyServiceHandler::onShutdown));
|
||||
_socket.setBlocking(false);
|
||||
}
|
||||
|
||||
~DummyServiceHandler()
|
||||
{
|
||||
_reactor.removeEventHandler(_socket, Observer<DummyServiceHandler, ReadableNotification>(*this, &DummyServiceHandler::onReadable));
|
||||
_reactor.removeEventHandler(_socket, Observer<DummyServiceHandler, ShutdownNotification>(*this, &DummyServiceHandler::onShutdown));
|
||||
}
|
||||
|
||||
void onReadable(ReadableNotification* pNf)
|
||||
{
|
||||
pNf->release();
|
||||
char buffer[64];
|
||||
do
|
||||
{
|
||||
if (0 == _socket.receiveBytes(&buffer[0], sizeof(buffer)))
|
||||
break;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
void onShutdown(ShutdownNotification* pNf)
|
||||
{
|
||||
pNf->release();
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
StreamSocket _socket;
|
||||
SocketReactor& _reactor;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -589,19 +628,40 @@ void SocketReactorTest::testDataCollection()
|
||||
|
||||
void SocketReactorTest::testSocketConnectorDeadlock()
|
||||
{
|
||||
SocketAddress ssa;
|
||||
ServerSocket ss(ssa);
|
||||
SocketAddress sa("127.0.0.1", ss.address().port());
|
||||
SocketReactor reactor;
|
||||
Thread thread;
|
||||
{
|
||||
SocketAddress ssa;
|
||||
ServerSocket ss(ssa);
|
||||
SocketAddress sa("127.0.0.1", ss.address().port());
|
||||
SocketReactor reactor;
|
||||
Thread thread;
|
||||
int i = 0;
|
||||
while (++i < 10)
|
||||
{
|
||||
auto sc = new SocketConnector<SleepClientServiceHandler>(sa, reactor);
|
||||
thread.startFunc([&reactor]() { reactor.run(); });
|
||||
reactor.stop();
|
||||
thread.join();
|
||||
delete sc;
|
||||
}
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while (++i < 10)
|
||||
{
|
||||
auto sc = new SocketConnector<SleepClientServiceHandler>(sa, reactor);
|
||||
thread.startFunc([&reactor]() { reactor.run(); });
|
||||
SocketAddress ssa;
|
||||
ServerSocket ss(ssa);
|
||||
SocketReactor reactor;
|
||||
SocketAcceptor<DummyServiceHandler> acceptor(ss, reactor);
|
||||
Thread thread;
|
||||
thread.start(reactor);
|
||||
|
||||
SocketAddress sa("127.0.0.1", ss.address().port());
|
||||
StreamSocket sock(sa);
|
||||
|
||||
std::string data("HELLO");
|
||||
sock.sendBytes(data.data(), static_cast<int>(data.size()));
|
||||
reactor.stop();
|
||||
thread.join();
|
||||
delete sc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user