|
|
|
@ -69,28 +69,19 @@ class MockTcpHandler : public ISrsTcpHandler
|
|
|
|
|
private:
|
|
|
|
|
srs_netfd_t fd;
|
|
|
|
|
public:
|
|
|
|
|
MockTcpHandler();
|
|
|
|
|
virtual ~MockTcpHandler();
|
|
|
|
|
MockTcpHandler() {
|
|
|
|
|
fd = NULL;
|
|
|
|
|
}
|
|
|
|
|
virtual ~MockTcpHandler() {
|
|
|
|
|
srs_close_stfd(fd);
|
|
|
|
|
}
|
|
|
|
|
public:
|
|
|
|
|
virtual srs_error_t on_tcp_client(srs_netfd_t stfd);
|
|
|
|
|
virtual srs_error_t on_tcp_client(srs_netfd_t stfd) {
|
|
|
|
|
fd = stfd;
|
|
|
|
|
return srs_success;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
MockTcpHandler::MockTcpHandler()
|
|
|
|
|
{
|
|
|
|
|
fd = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MockTcpHandler::~MockTcpHandler()
|
|
|
|
|
{
|
|
|
|
|
srs_close_stfd(fd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
srs_error_t MockTcpHandler::on_tcp_client(srs_netfd_t stfd)
|
|
|
|
|
{
|
|
|
|
|
fd = stfd;
|
|
|
|
|
return srs_success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID TEST(TCPServerTest, PingPong)
|
|
|
|
|
{
|
|
|
|
|
srs_error_t err;
|
|
|
|
@ -1459,7 +1450,7 @@ public:
|
|
|
|
|
int r0;
|
|
|
|
|
int r1;
|
|
|
|
|
SrsFastCoroutine trd;
|
|
|
|
|
MockStopSelfThread() : trd("mock", this), r0(0), r1(0) {
|
|
|
|
|
MockStopSelfThread() : r0(0), r1(0), trd("mock", this) {
|
|
|
|
|
}
|
|
|
|
|
virtual ~MockStopSelfThread() {
|
|
|
|
|
}
|
|
|
|
@ -1476,12 +1467,88 @@ public:
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
VOID TEST(StopSelfThreadTest, ShouldFailWhenStopSelf)
|
|
|
|
|
VOID TEST(ThreadCriticalTest, ShouldFailWhenStopSelf)
|
|
|
|
|
{
|
|
|
|
|
srs_error_t err;
|
|
|
|
|
MockStopSelfThread trd;
|
|
|
|
|
trd.start();
|
|
|
|
|
HELPER_EXPECT_SUCCESS(trd.start());
|
|
|
|
|
|
|
|
|
|
// Switch to thread cycle, should fail.
|
|
|
|
|
srs_usleep(0);
|
|
|
|
|
EXPECT_EQ(-1, trd.r0);
|
|
|
|
|
EXPECT_EQ(EDEADLK, trd.r1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class MockAsyncReaderThread : public ISrsCoroutineHandler
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
SrsFastCoroutine trd;
|
|
|
|
|
srs_netfd_t fd;
|
|
|
|
|
MockAsyncReaderThread(srs_netfd_t v) : trd("mock", this), fd(v) {
|
|
|
|
|
}
|
|
|
|
|
virtual ~MockAsyncReaderThread() {
|
|
|
|
|
}
|
|
|
|
|
srs_error_t start() {
|
|
|
|
|
return trd.start();
|
|
|
|
|
}
|
|
|
|
|
void stop() {
|
|
|
|
|
trd.stop();
|
|
|
|
|
}
|
|
|
|
|
virtual srs_error_t cycle() {
|
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
while (true) {
|
|
|
|
|
if ((err = trd.pull()) != srs_success) {
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
char buf[16] = {0};
|
|
|
|
|
if (st_read((st_netfd_t)fd, buf, sizeof(buf), SRS_UTIME_NO_TIMEOUT) <= 0) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
VOID TEST(ThreadCriticalTest, FailIfCloseActiveFD)
|
|
|
|
|
{
|
|
|
|
|
srs_error_t err;
|
|
|
|
|
|
|
|
|
|
MockTcpHandler h;
|
|
|
|
|
SrsTcpListener l(&h, _srs_tmp_host, _srs_tmp_port);
|
|
|
|
|
HELPER_EXPECT_SUCCESS(l.listen());
|
|
|
|
|
|
|
|
|
|
SrsTcpClient c0(_srs_tmp_host, _srs_tmp_port, _srs_tmp_timeout);
|
|
|
|
|
HELPER_EXPECT_SUCCESS(c0.connect());
|
|
|
|
|
|
|
|
|
|
srs_usleep(30 * SRS_UTIME_MILLISECONDS);
|
|
|
|
|
EXPECT_TRUE(h.fd != NULL);
|
|
|
|
|
|
|
|
|
|
MockAsyncReaderThread trd0(h.fd);
|
|
|
|
|
HELPER_EXPECT_SUCCESS(trd0.start());
|
|
|
|
|
|
|
|
|
|
MockAsyncReaderThread trd1(h.fd);
|
|
|
|
|
HELPER_EXPECT_SUCCESS(trd1.start());
|
|
|
|
|
|
|
|
|
|
// Wait for all threads to run.
|
|
|
|
|
srs_usleep(10 * SRS_UTIME_MILLISECONDS);
|
|
|
|
|
|
|
|
|
|
// Should fail when close, because there is 2 threads reading fd.
|
|
|
|
|
int r0 = st_netfd_close((st_netfd_t)h.fd);
|
|
|
|
|
EXPECT_EQ(-1, r0);
|
|
|
|
|
EXPECT_EQ(EBUSY, errno);
|
|
|
|
|
|
|
|
|
|
// Stop thread1, still fail because thread0 is reading fd.
|
|
|
|
|
trd1.stop();
|
|
|
|
|
r0 = st_netfd_close((st_netfd_t)h.fd);
|
|
|
|
|
EXPECT_EQ(-1, r0);
|
|
|
|
|
EXPECT_EQ(EBUSY, errno);
|
|
|
|
|
|
|
|
|
|
// Stop thread0, should success, no threads is reading fd.
|
|
|
|
|
trd0.stop();
|
|
|
|
|
r0 = st_netfd_close((st_netfd_t)h.fd);
|
|
|
|
|
EXPECT_EQ(0, r0);
|
|
|
|
|
|
|
|
|
|
// Set fd to NULL to avoid close fail for EBADF.
|
|
|
|
|
h.fd = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|