From df7faa16031aec8df877605f9478ab6f67331205 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 4 Nov 2021 08:47:40 +0800 Subject: [PATCH] For #2369, #1708, #1941: Add utest to cover fail for close or stop --- trunk/src/utest/srs_utest_service.cpp | 111 +++++++++++++++++++++----- 1 file changed, 89 insertions(+), 22 deletions(-) diff --git a/trunk/src/utest/srs_utest_service.cpp b/trunk/src/utest/srs_utest_service.cpp index c9d13ac3ec..d9f381dbaa 100644 --- a/trunk/src/utest/srs_utest_service.cpp +++ b/trunk/src/utest/srs_utest_service.cpp @@ -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 @@ class MockStopSelfThread : public ISrsCoroutineHandler 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 @@ class MockStopSelfThread : public ISrsCoroutineHandler } }; -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; +} +