diff --git a/trunk/3rdparty/st-srs/Makefile b/trunk/3rdparty/st-srs/Makefile index 11fdc95c99..8fb418c57a 100644 --- a/trunk/3rdparty/st-srs/Makefile +++ b/trunk/3rdparty/st-srs/Makefile @@ -185,11 +185,9 @@ endif # make EXTRA_CFLAGS=-UMD_HAVE_EPOLL # # or to enable sendmmsg(2) support: -# # make EXTRA_CFLAGS="-DMD_HAVE_SENDMMSG -D_GNU_SOURCE" # # or to enable stats for ST: -# # make EXTRA_CFLAGS=-DDEBUG_STATS # # or cache the stack and reuse it: @@ -201,6 +199,9 @@ endif # or enable support for asan: # make EXTRA_CFLAGS="-DMD_ASAN -fsanitize=address -fno-omit-frame-pointer" # +# or to disable the clock_gettime for MacOS before 10.12, see https://github.com/ossrs/srs/issues/3978 +# make EXTRA_CFLAGS=-DMD_OSX_NO_CLOCK_GETTIME +# # or enable the coverage for utest: # make UTEST_FLAGS="-fprofile-arcs -ftest-coverage" # diff --git a/trunk/3rdparty/st-srs/md.h b/trunk/3rdparty/st-srs/md.h index 677d6fb464..a25c0087af 100644 --- a/trunk/3rdparty/st-srs/md.h +++ b/trunk/3rdparty/st-srs/md.h @@ -101,10 +101,21 @@ extern void _st_md_cxt_restore(_st_jmp_buf_t env, int val); #error Unknown CPU architecture #endif - #define MD_GET_UTIME() \ - struct timeval tv; \ - (void) gettimeofday(&tv, NULL); \ - return (tv.tv_sec * 1000000LL + tv.tv_usec) + #if defined (MD_OSX_NO_CLOCK_GETTIME) + #define MD_GET_UTIME() \ + struct timeval tv; \ + (void) gettimeofday(&tv, NULL); \ + return (tv.tv_sec * 1000000LL + tv.tv_usec) + #else + /* + * https://github.com/ossrs/srs/issues/3978 + * use clock_gettime to get the timestamp in microseconds. + */ + #define MD_GET_UTIME() \ + struct timespec ts; \ + clock_gettime(CLOCK_MONOTONIC, &ts); \ + return (ts.tv_sec * 1000000LL + ts.tv_nsec / 1000) + #endif #elif defined (LINUX) @@ -120,13 +131,13 @@ extern void _st_md_cxt_restore(_st_jmp_buf_t env, int val); #define MD_HAVE_SOCKLEN_T /* - * All architectures and flavors of linux have the gettimeofday - * function but if you know of a faster way, use it. + * https://github.com/ossrs/srs/issues/3978 + * use clock_gettime to get the timestamp in microseconds. */ - #define MD_GET_UTIME() \ - struct timeval tv; \ - (void) gettimeofday(&tv, NULL); \ - return (tv.tv_sec * 1000000LL + tv.tv_usec) + #define MD_GET_UTIME() \ + struct timespec ts; \ + clock_gettime(CLOCK_MONOTONIC, &ts); \ + return (ts.tv_sec * 1000000LL + ts.tv_nsec / 1000) #if defined(__i386__) #define MD_GET_SP(_t) *((long *)&((_t)->context[0].__jmpbuf[4])) diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index a73b6b8b55..349feec2fb 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -266,6 +266,9 @@ fi # for osx, use darwin for st, donot use epoll. if [[ $SRS_OSX == YES ]]; then _ST_MAKE=darwin-debug && _ST_OBJ="DARWIN_`uname -r`_DBG" + if [[ $SRS_OSX_HAS_CLOCK_GETTIME != YES ]]; then + _ST_EXTRA_CFLAGS="$_ST_EXTRA_CFLAGS -DMD_OSX_NO_CLOCK_GETTIME" + fi fi # for windows/cygwin if [[ $SRS_CYGWIN64 = YES ]]; then diff --git a/trunk/auto/options.sh b/trunk/auto/options.sh index 03d58c54cd..e5dcfeda92 100755 --- a/trunk/auto/options.sh +++ b/trunk/auto/options.sh @@ -112,6 +112,8 @@ SRS_CROSS_BUILD_HOST= SRS_CROSS_BUILD_PREFIX= # For cache build SRS_BUILD_CACHE=YES +# Only support MacOS 10.12+ for clock_gettime, see https://github.com/ossrs/srs/issues/3978 +SRS_OSX_HAS_CLOCK_GETTIME=YES # ##################################################################################### # Toolchain for cross-build on Ubuntu for ARM or MIPS. @@ -150,7 +152,9 @@ function apply_system_options() { OS_IS_RISCV=$(gcc -dM -E - /dev/null || echo 1); fi diff --git a/trunk/configure b/trunk/configure index b9475493ed..b7f004059a 100755 --- a/trunk/configure +++ b/trunk/configure @@ -464,7 +464,8 @@ if [[ $SRS_UTEST == YES ]]; then MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_kernel" "srs_utest_core" "srs_utest_config" "srs_utest_rtmp" "srs_utest_http" "srs_utest_avc" "srs_utest_reload" "srs_utest_mp4" "srs_utest_service" "srs_utest_app" "srs_utest_rtc" "srs_utest_config2" - "srs_utest_protocol" "srs_utest_protocol2" "srs_utest_kernel2" "srs_utest_protocol3") + "srs_utest_protocol" "srs_utest_protocol2" "srs_utest_kernel2" "srs_utest_protocol3" + "srs_utest_st") if [[ $SRS_SRT == YES ]]; then MODULE_FILES+=("srs_utest_srt") fi diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md index 9e676930f2..18a7b36a43 100644 --- a/trunk/doc/CHANGELOG.md +++ b/trunk/doc/CHANGELOG.md @@ -7,6 +7,7 @@ The changelog for SRS. ## SRS 7.0 Changelog +* v7.0, 2024-10-15, Merge [#3979](https://github.com/ossrs/srs/pull/3979): ST: Use clock_gettime to prevent time jumping backwards. v7.0.17 (#3979) * v7.0, 2024-09-09, Merge [#4158](https://github.com/ossrs/srs/pull/4158): Proxy: Support proxy server for SRS. v7.0.16 (#4158) * v7.0, 2024-09-09, Merge [#4171](https://github.com/ossrs/srs/pull/4171): Heartbeat: Report ports for proxy server. v7.0.15 (#4171) * v7.0, 2024-09-01, Merge [#4165](https://github.com/ossrs/srs/pull/4165): FLV: Refine source and http handler. v7.0.14 (#4165) diff --git a/trunk/src/core/srs_core_version7.hpp b/trunk/src/core/srs_core_version7.hpp index 458a6c3d84..67461fab92 100644 --- a/trunk/src/core/srs_core_version7.hpp +++ b/trunk/src/core/srs_core_version7.hpp @@ -9,6 +9,6 @@ #define VERSION_MAJOR 7 #define VERSION_MINOR 0 -#define VERSION_REVISION 16 +#define VERSION_REVISION 17 #endif \ No newline at end of file diff --git a/trunk/src/utest/srs_utest_st.cpp b/trunk/src/utest/srs_utest_st.cpp new file mode 100644 index 0000000000..553bc0c95f --- /dev/null +++ b/trunk/src/utest/srs_utest_st.cpp @@ -0,0 +1,117 @@ +// +// Copyright (c) 2013-2024 The SRS Authors +// +// SPDX-License-Identifier: MIT +// +#include +#include +#include +#include + +using namespace std; + +VOID TEST(StTest, StUtimeInMicroseconds) +{ + st_utime_t st_time_1 = st_utime(); + // sleep 1 microsecond +#if !defined(SRS_CYGWIN64) + usleep(1); +#endif + st_utime_t st_time_2 = st_utime(); + + EXPECT_GT(st_time_1, 0); + EXPECT_GT(st_time_2, 0); + EXPECT_GE(st_time_2, st_time_1); + // st_time_2 - st_time_1 should be in range of [1, 100] microseconds + EXPECT_GE(st_time_2 - st_time_1, 0); + EXPECT_LE(st_time_2 - st_time_1, 100); +} + +static inline st_utime_t time_gettimeofday() { + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec * 1000000LL + tv.tv_usec); +} + +VOID TEST(StTest, StUtimePerformance) +{ + clock_t start; + int gettimeofday_elapsed_time = 0; + int st_utime_elapsed_time = 0; + + // Both the st_utime(clock_gettime or gettimeofday) and gettimeofday's + // elpased time to execute is dependence on whether it is the first time be called. + // In general, the gettimeofday has better performance, but the gap between + // them is really small, maybe less than 10 clock ~ 10 microseconds. + + // check st_utime first, then gettimeofday + { + start = clock(); + st_utime_t t2 = st_utime(); + int elapsed_time = clock() - start; + st_utime_elapsed_time += elapsed_time; + EXPECT_GT(t2, 0); + + start = clock(); + st_utime_t t1 = time_gettimeofday(); + elapsed_time = clock() - start; + gettimeofday_elapsed_time += elapsed_time; + EXPECT_GT(t1, 0); + + + EXPECT_GE(gettimeofday_elapsed_time, 0); + EXPECT_GE(st_utime_elapsed_time, 0); + + // pass the test, if + EXPECT_LT(gettimeofday_elapsed_time > st_utime_elapsed_time ? + gettimeofday_elapsed_time - st_utime_elapsed_time : + st_utime_elapsed_time - gettimeofday_elapsed_time, 10); + } + + // check gettimeofday first, then st_utime + { + start = clock(); + st_utime_t t1 = time_gettimeofday(); + int elapsed_time = clock() - start; + gettimeofday_elapsed_time += elapsed_time; + EXPECT_GT(t1, 0); + + start = clock(); + st_utime_t t2 = st_utime(); + elapsed_time = clock() - start; + st_utime_elapsed_time += elapsed_time; + EXPECT_GT(t2, 0); + + EXPECT_GE(gettimeofday_elapsed_time, 0); + EXPECT_GE(st_utime_elapsed_time, 0); + + EXPECT_LT(gettimeofday_elapsed_time > st_utime_elapsed_time ? + gettimeofday_elapsed_time - st_utime_elapsed_time : + st_utime_elapsed_time - gettimeofday_elapsed_time, 10); + } + + // compare st_utime & gettimeofday in a loop + for (int i = 0; i < 100; i++) { + start = clock(); + st_utime_t t2 = st_utime(); + int elapsed_time = clock() - start; + st_utime_elapsed_time = elapsed_time; + EXPECT_GT(t2, 0); + usleep(1); + + start = clock(); + st_utime_t t1 = time_gettimeofday(); + elapsed_time = clock() - start; + gettimeofday_elapsed_time = elapsed_time; + EXPECT_GT(t1, 0); + usleep(1); + + EXPECT_GE(gettimeofday_elapsed_time, 0); + EXPECT_GE(st_utime_elapsed_time, 0); + + EXPECT_LT(gettimeofday_elapsed_time > st_utime_elapsed_time ? + gettimeofday_elapsed_time - st_utime_elapsed_time : + st_utime_elapsed_time - gettimeofday_elapsed_time, 10); + + } +} diff --git a/trunk/src/utest/srs_utest_st.hpp b/trunk/src/utest/srs_utest_st.hpp new file mode 100644 index 0000000000..32862447a7 --- /dev/null +++ b/trunk/src/utest/srs_utest_st.hpp @@ -0,0 +1,15 @@ +// +// Copyright (c) 2013-2024 The SRS Authors +// +// SPDX-License-Identifier: MIT +// + +#ifndef SRS_UTEST_ST_HPP +#define SRS_UTEST_ST_HPP + +#include + +#include + +#endif // SRS_UTEST_ST_HPP +