diff --git a/trunk/src/app/srs_app_st.cpp b/trunk/src/app/srs_app_st.cpp index 243fae0ef..34b33652f 100755 --- a/trunk/src/app/srs_app_st.cpp +++ b/trunk/src/app/srs_app_st.cpp @@ -101,8 +101,12 @@ srs_error_t SrsSTCoroutine::start() srs_error_t err = srs_success; if (started || disposed) { - err = srs_error_new(ERROR_THREAD_DISPOSED, "failed for disposed=%d, started=%d", disposed, started); - + if (disposed) { + err = srs_error_new(ERROR_THREAD_DISPOSED, "disposed"); + } else { + err = srs_error_new(ERROR_THREAD_STARTED, "started"); + } + if (trd_err == srs_success) { trd_err = srs_error_copy(err); } diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index e5b2fece8..62c776636 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -114,6 +114,7 @@ #define ERROR_SOCKET_SETKEEPALIVE 1075 #define ERROR_SOCKET_NO_NODELAY 1076 #define ERROR_SOCKET_SNDBUF 1077 +#define ERROR_THREAD_STARTED 1078 /////////////////////////////////////////////////////// // RTMP protocol error. diff --git a/trunk/src/utest/srs_utest_app.cpp b/trunk/src/utest/srs_utest_app.cpp index 4a3388efd..ee52a349f 100644 --- a/trunk/src/utest/srs_utest_app.cpp +++ b/trunk/src/utest/srs_utest_app.cpp @@ -87,10 +87,9 @@ public: SrsSTCoroutine* trd; srs_error_t err; srs_cond_t running; + int cid; public: - MockCoroutineHandler() { - trd = NULL; - err = srs_success; + MockCoroutineHandler() : trd(NULL), err(srs_success), cid(0) { running = srs_cond_new(); } virtual ~MockCoroutineHandler() { @@ -101,14 +100,17 @@ public: srs_error_t r0 = srs_success; srs_cond_signal(running); + cid = _srs_context->get_id(); - while ((r0 = trd->pull()) == srs_success) { - if (err != srs_success) { - return err; - } + while ((r0 = trd->pull()) == srs_success && err == srs_success) { srs_usleep(10 * 1000); } + if (err != srs_success) { + srs_freep(r0); + return err; + } + return r0; } }; @@ -164,6 +166,90 @@ VOID TEST(AppCoroutineTest, StartStop) EXPECT_TRUE(ERROR_THREAD_DISPOSED == srs_error_code(err)); srs_freep(err); } + + if (true) { + MockCoroutineHandler ch; + SrsSTCoroutine sc("test", &ch); + ch.trd = ≻ + EXPECT_EQ(0, sc.cid()); + + EXPECT_TRUE(srs_success == sc.start()); + EXPECT_TRUE(srs_success == sc.pull()); + + // Error when start multiple times. + srs_error_t err = sc.start(); + EXPECT_TRUE(srs_success != err); + EXPECT_TRUE(ERROR_THREAD_STARTED == srs_error_code(err)); + srs_freep(err); + + err = sc.pull(); + EXPECT_TRUE(srs_success != err); + EXPECT_TRUE(ERROR_THREAD_STARTED == srs_error_code(err)); + srs_freep(err); + } +} + +VOID TEST(AppCoroutineTest, Cycle) +{ + if (true) { + MockCoroutineHandler ch; + SrsSTCoroutine sc("test", &ch); + ch.trd = ≻ + + EXPECT_TRUE(srs_success == sc.start()); + EXPECT_TRUE(srs_success == sc.pull()); + + // Set cycle to error. + ch.err = srs_error_new(-1, "cycle"); + + srs_cond_timedwait(ch.running, 100 * SRS_UTIME_MILLISECONDS); + + // The cycle error should be pulled. + srs_error_t err = sc.pull(); + EXPECT_TRUE(srs_success != err); + EXPECT_TRUE(-1 == srs_error_code(err)); + srs_freep(err); + } + + if (true) { + MockCoroutineHandler ch; + SrsSTCoroutine sc("test", &ch, 250); + ch.trd = ≻ + EXPECT_EQ(250, sc.cid()); + + EXPECT_TRUE(srs_success == sc.start()); + EXPECT_TRUE(srs_success == sc.pull()); + + // After running, the cid in cycle should equal to the thread. + srs_cond_timedwait(ch.running, 100 * SRS_UTIME_MILLISECONDS); + EXPECT_EQ(250, ch.cid); + } + + if (true) { + MockCoroutineHandler ch; + SrsSTCoroutine sc("test", &ch); + ch.trd = ≻ + + EXPECT_TRUE(srs_success == sc.start()); + EXPECT_TRUE(srs_success == sc.pull()); + + srs_cond_timedwait(ch.running, 100 * SRS_UTIME_MILLISECONDS); + + // Interrupt thread, set err to interrupted. + sc.interrupt(); + + // Set cycle to error. + ch.err = srs_error_new(-1, "cycle"); + + // Override the error by cycle error. + sc.stop(); + + // Should be cycle error. + srs_error_t err = sc.pull(); + EXPECT_TRUE(srs_success != err); + EXPECT_TRUE(-1 == srs_error_code(err)); + srs_freep(err); + } } #endif