From 8248c3d9df89387d9302e0cf97e43ae02ea85aa8 Mon Sep 17 00:00:00 2001 From: Yakun Xu Date: Sat, 20 Jun 2020 07:12:55 +0800 Subject: [PATCH] [posix] use real time signal for microsecond timer (#5122) --- Android.mk | 2 + examples/platforms/simulation/alarm.c | 30 +++--- script/test | 4 +- src/posix/Makefile.am | 6 ++ src/posix/main.c | 23 +++++ src/posix/platform/CMakeLists.txt | 9 +- src/posix/platform/alarm.cpp | 99 +++++++++++++++++-- .../include/openthread/openthread-system.h | 7 +- src/posix/platform/platform-posix.h | 5 +- src/posix/platform/system.cpp | 2 +- tests/scripts/thread-cert/node.py | 8 +- 11 files changed, 160 insertions(+), 35 deletions(-) diff --git a/Android.mk b/Android.mk index 1bdeffa65..97907a282 100644 --- a/Android.mk +++ b/Android.mk @@ -396,6 +396,7 @@ LOCAL_CPPFLAGS := \ $(NULL) LOCAL_LDLIBS := \ + -lrt \ -lutil LOCAL_SRC_FILES := \ @@ -481,6 +482,7 @@ LOCAL_SRC_FILES := \ $(NULL) LOCAL_LDLIBS := \ + -lrt \ -lutil LOCAL_STATIC_LIBRARIES = libopenthread-ncp ot-core diff --git a/examples/platforms/simulation/alarm.c b/examples/platforms/simulation/alarm.c index d31c03f50..4157e5e59 100644 --- a/examples/platforms/simulation/alarm.c +++ b/examples/platforms/simulation/alarm.c @@ -36,13 +36,7 @@ #include "utils/code_utils.h" -#ifndef __linux__ -#define __linux__ 0 -#endif - -// linux microsecond timer -#if __linux__ - +#ifdef __linux__ #include #include @@ -67,6 +61,12 @@ timer_t sMicroTimer; #define DEFAULT_TIMEOUT 10 // seconds +#ifdef CLOCK_MONOTONIC_RAW +#define OT_SIMULATION_CLOCK_ID CLOCK_MONOTONIC_RAW +#else +#define OT_SIMULATION_CLOCK_ID CLOCK_MONOTONIC +#endif + static bool sIsMsRunning = false; static uint32_t sMsAlarm = 0; @@ -75,7 +75,7 @@ static uint32_t sUsAlarm = 0; static uint32_t sSpeedUpFactor = 1; -#if __linux__ +#ifdef __linux__ static void microTimerHandler(int aSignal, siginfo_t *aSignalInfo, void *aUserContext) { assert(aSignal == OPENTHREAD_CONFIG_MICRO_TIMER_SIGNAL); @@ -90,7 +90,7 @@ void platformAlarmInit(uint32_t aSpeedUpFactor) { sSpeedUpFactor = aSpeedUpFactor; -#if __linux__ +#ifdef __linux__ { struct sigaction sa; @@ -110,7 +110,7 @@ void platformAlarmInit(uint32_t aSpeedUpFactor) sev.sigev_signo = OPENTHREAD_CONFIG_MICRO_TIMER_SIGNAL; sev.sigev_value.sival_ptr = &sMicroTimer; - if (-1 == timer_create(CLOCK_REALTIME, &sev, &sMicroTimer)) + if (-1 == timer_create(CLOCK_MONOTONIC, &sev, &sMicroTimer)) { perror("timer_create"); exit(EXIT_FAILURE); @@ -125,11 +125,7 @@ uint64_t platformGetNow(void) struct timespec now; int err; -#ifdef CLOCK_MONOTONIC_RAW - err = clock_gettime(CLOCK_MONOTONIC_RAW, &now); -#else - err = clock_gettime(CLOCK_MONOTONIC, &now); -#endif + err = clock_gettime(OT_SIMULATION_CLOCK_ID, &now); VerifyOrDie(err == 0, OT_EXIT_ERROR_ERRNO); @@ -181,7 +177,7 @@ void otPlatAlarmMicroStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt) sUsAlarm = aT0 + aDt; sIsUsRunning = true; -#if __linux__ +#ifdef __linux__ { struct itimerspec its; uint32_t diff = sUsAlarm - otPlatAlarmMicroGetNow(); @@ -207,7 +203,7 @@ void otPlatAlarmMicroStop(otInstance *aInstance) sIsUsRunning = false; -#if __linux__ +#ifdef __linux__ { struct itimerspec its = {{0, 0}, {0, 0}}; diff --git a/script/test b/script/test index 1d01cf0a0..63d36008c 100755 --- a/script/test +++ b/script/test @@ -49,7 +49,7 @@ readonly VIRTUAL_TIME="${VIRTUAL_TIME:-1}" build_simulation() { local version="$1" - local options=("-DOT_THREAD_VERSION=${version}") + local options=("-DOT_THREAD_VERSION=${version}" "-DBUILD_TESTING=ON") if [[ ${version} == "1.2" ]]; then options+=("-DOT_DUA=ON") @@ -82,7 +82,7 @@ build_simulation() build_posix() { local version="$1" - local options=("-DOT_THREAD_VERSION=${version}") + local options=("-DOT_THREAD_VERSION=${version}" "-DBUILD_TESTING=ON") if [[ ${version} == "1.2" ]]; then options+=("-DOT_DUA=ON") diff --git a/src/posix/Makefile.am b/src/posix/Makefile.am index fd2bfbb1f..18b09dfbe 100644 --- a/src/posix/Makefile.am +++ b/src/posix/Makefile.am @@ -60,6 +60,12 @@ LDADD_COMMON = \ -lutil \ $(NULL) +if OPENTHREAD_TARGET_LINUX +LDADD_COMMON += \ + -lrt \ + $(NULL) +endif + if OPENTHREAD_ENABLE_BUILTIN_MBEDTLS LDADD_COMMON += \ $(top_builddir)/third_party/mbedtls/libmbedcrypto.a \ diff --git a/src/posix/main.c b/src/posix/main.c index 9bb422d6a..d77d114e5 100644 --- a/src/posix/main.c +++ b/src/posix/main.c @@ -113,6 +113,7 @@ enum OT_POSIX_OPT_SHORT_MAX = 128, OT_POSIX_OPT_RADIO_VERSION, + OT_POSIX_OPT_REAL_TIME_SIGNAL, }; static const struct option kOptions[] = {{"debug-level", required_argument, NULL, OT_POSIX_OPT_DEBUG_LEVEL}, @@ -120,6 +121,7 @@ static const struct option kOptions[] = {{"debug-level", required_argument, NULL {"help", no_argument, NULL, OT_POSIX_OPT_HELP}, {"interface-name", required_argument, NULL, OT_POSIX_OPT_INTERFACE_NAME}, {"radio-version", no_argument, NULL, OT_POSIX_OPT_RADIO_VERSION}, + {"real-time-signal", required_argument, NULL, OT_POSIX_OPT_REAL_TIME_SIGNAL}, {"time-speed", required_argument, NULL, OT_POSIX_OPT_TIME_SPEED}, {"verbose", no_argument, NULL, OT_POSIX_OPT_VERBOSE}, {0, 0, 0, 0}}; @@ -138,6 +140,12 @@ static void PrintUsage(const char *aProgramName, FILE *aStream, int aExitCode) " -s --time-speed factor Time speed up factor.\n" " -v --verbose Also log to stderr.\n", aProgramName); +#ifdef __linux__ + fprintf(aStream, + " --real-time-signal (Linux only) The real-time signal number for microsecond timer.\n" + " Use +N for relative value to SIGRTMIN, and use N for absolute value.\n"); + +#endif fprintf(aStream, "%s", otSysGetRadioUrlHelpString()); exit(aExitCode); } @@ -148,6 +156,9 @@ static void ParseArg(int aArgCount, char *aArgVector[], PosixConfig *aConfig) aConfig->mPlatformConfig.mSpeedUpFactor = 1; aConfig->mLogLevel = OT_LOG_LEVEL_CRIT; +#ifdef __linux__ + aConfig->mPlatformConfig.mRealTimeSignal = SIGRTMIN; +#endif optind = 1; @@ -194,6 +205,18 @@ static void ParseArg(int aArgCount, char *aArgVector[], PosixConfig *aConfig) case OT_POSIX_OPT_RADIO_VERSION: aConfig->mPrintRadioVersion = true; break; +#ifdef __linux__ + case OT_POSIX_OPT_REAL_TIME_SIGNAL: + if (optarg[0] == '+') + { + aConfig->mPlatformConfig.mRealTimeSignal = SIGRTMIN + atoi(&optarg[1]); + } + else + { + aConfig->mPlatformConfig.mRealTimeSignal = atoi(optarg); + } + break; +#endif // __linux__ case '?': PrintUsage(aArgVector[0], stderr, OT_EXIT_INVALID_ARGUMENTS); break; diff --git a/src/posix/platform/CMakeLists.txt b/src/posix/platform/CMakeLists.txt index e509b2eda..4a36913aa 100644 --- a/src/posix/platform/CMakeLists.txt +++ b/src/posix/platform/CMakeLists.txt @@ -83,7 +83,14 @@ set_target_properties( CXX_STANDARD 11 ) -target_link_libraries(openthread-posix PUBLIC openthread-platform PRIVATE ot-config util) +target_link_libraries(openthread-posix + PUBLIC + openthread-platform + PRIVATE + ot-config + util + $<$:rt> +) target_compile_definitions(openthread-posix PUBLIC diff --git a/src/posix/platform/alarm.cpp b/src/posix/platform/alarm.cpp index fc28af936..0dfdddc0b 100644 --- a/src/posix/platform/alarm.cpp +++ b/src/posix/platform/alarm.cpp @@ -50,16 +50,38 @@ static uint32_t sUsAlarm = 0; static uint32_t sSpeedUpFactor = 1; +#ifdef __linux__ + +#include +#include + +#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE && !OPENTHREAD_POSIX_VIRTUAL_TIME +static timer_t sMicroTimer; +static int sRealTimeSignal = 0; + +static void microTimerHandler(int aSignal, siginfo_t *aSignalInfo, void *aUserContext) +{ + assert(aSignal == sRealTimeSignal); + assert(aSignalInfo->si_value.sival_ptr == &sMicroTimer); + OT_UNUSED_VARIABLE(aSignal); + OT_UNUSED_VARIABLE(aSignalInfo); + OT_UNUSED_VARIABLE(aUserContext); +} +#endif // OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE && !OPENTHREAD_POSIX_VIRTUAL_TIME +#endif // __linux__ + +#ifdef CLOCK_MONOTONIC_RAW +#define OT_POSIX_CLOCK_ID CLOCK_MONOTONIC_RAW +#else +#define OT_POSIX_CLOCK_ID CLOCK_MONOTONIC +#endif + #if !OPENTHREAD_POSIX_VIRTUAL_TIME uint64_t otPlatTimeGet(void) { struct timespec now; -#ifdef CLOCK_MONOTONIC_RAW - VerifyOrDie(clock_gettime(CLOCK_MONOTONIC_RAW, &now) == 0, OT_EXIT_FAILURE); -#else - VerifyOrDie(clock_gettime(CLOCK_MONOTONIC, &now) == 0, OT_EXIT_FAILURE); -#endif + VerifyOrDie(clock_gettime(OT_POSIX_CLOCK_ID, &now) == 0, OT_EXIT_FAILURE); return (uint64_t)now.tv_sec * US_PER_S + (uint64_t)now.tv_nsec / NS_PER_US; } @@ -70,9 +92,43 @@ static uint64_t platformAlarmGetNow(void) return otPlatTimeGet() * sSpeedUpFactor; } -void platformAlarmInit(uint32_t aSpeedUpFactor) +void platformAlarmInit(uint32_t aSpeedUpFactor, int aRealTimeSignal) { sSpeedUpFactor = aSpeedUpFactor; + + if (aRealTimeSignal == 0) + { +#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE + otLogWarnPlat("Real time signal not enabled, microsecond timers may be inaccurate!"); +#endif + } +#ifdef __linux__ + else if (aRealTimeSignal >= SIGRTMIN && aRealTimeSignal <= SIGRTMAX) + { +#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE && !OPENTHREAD_POSIX_VIRTUAL_TIME + struct sigaction sa; + struct sigevent sev; + + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = microTimerHandler; + sigemptyset(&sa.sa_mask); + + VerifyOrDie(sigaction(aRealTimeSignal, &sa, NULL) != -1, OT_EXIT_ERROR_ERRNO); + + sev.sigev_notify = SIGEV_SIGNAL; + sev.sigev_signo = aRealTimeSignal; + sev.sigev_value.sival_ptr = &sMicroTimer; + + VerifyOrDie(timer_create(CLOCK_MONOTONIC, &sev, &sMicroTimer) != -1, OT_EXIT_ERROR_ERRNO); + + sRealTimeSignal = aRealTimeSignal; +#endif // OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE && !OPENTHREAD_POSIX_VIRTUAL_TIME + } +#endif // __linux__ + else + { + DieNow(OT_EXIT_INVALID_ARGUMENTS); + } } uint32_t otPlatAlarmMilliGetNow(void) @@ -107,6 +163,25 @@ void otPlatAlarmMicroStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt) sUsAlarm = aT0 + aDt; sIsUsRunning = true; + +#ifdef __linux__ + if (sRealTimeSignal != 0) + { + struct itimerspec its; + uint32_t diff = sUsAlarm - otPlatAlarmMicroGetNow(); + + its.it_value.tv_sec = diff / US_PER_S; + its.it_value.tv_nsec = (diff % US_PER_S) * NS_PER_US; + + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + + if (-1 == timer_settime(sMicroTimer, 0, &its, NULL)) + { + otLogWarnPlat("Failed to update microsecond timer: %s", strerror(errno)); + } + } +#endif // __linux__ } void otPlatAlarmMicroStop(otInstance *aInstance) @@ -114,6 +189,18 @@ void otPlatAlarmMicroStop(otInstance *aInstance) OT_UNUSED_VARIABLE(aInstance); sIsUsRunning = false; + +#ifdef __linux__ + if (sRealTimeSignal != 0) + { + struct itimerspec its = {{0, 0}, {0, 0}}; + + if (-1 == timer_settime(sMicroTimer, 0, &its, NULL)) + { + otLogWarnPlat("Failed to stop microsecond timer: %s", strerror(errno)); + } + } +#endif // __linux__ } #endif // OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE diff --git a/src/posix/platform/include/openthread/openthread-system.h b/src/posix/platform/include/openthread/openthread-system.h index fcb24eb2a..3b2dc2728 100644 --- a/src/posix/platform/include/openthread/openthread-system.h +++ b/src/posix/platform/include/openthread/openthread-system.h @@ -76,9 +76,10 @@ typedef struct otPosixRadioArguments otPosixRadioArguments; */ typedef struct otPlatformConfig { - uint32_t mSpeedUpFactor; ///< Speed up factor. - const char *mInterfaceName; ///< Thread network interface name. - const char *mRadioUrl; ///< Radio url. + const char *mInterfaceName; ///< Thread network interface name. + const char *mRadioUrl; ///< Radio url. + int mRealTimeSignal; ///< The real-time signal for microsecond timer. + uint32_t mSpeedUpFactor; ///< Speed up factor. } otPlatformConfig; /** diff --git a/src/posix/platform/platform-posix.h b/src/posix/platform/platform-posix.h index 3b11ebe3a..9b78b8283 100644 --- a/src/posix/platform/platform-posix.h +++ b/src/posix/platform/platform-posix.h @@ -106,8 +106,11 @@ extern uint64_t gNodeId; /** * This function initializes the alarm service used by OpenThread. * + * @param[in] aSpeedUpFactor The speed up factor. + * @param[in] aRealTimeSignal The real time signal for microsecond alarms. + * */ -void platformAlarmInit(uint32_t aSpeedUpFactor); +void platformAlarmInit(uint32_t aSpeedUpFactor, int aRealTimeSignal); /** * This function retrieves the time remaining until the alarm fires. diff --git a/src/posix/platform/system.cpp b/src/posix/platform/system.cpp index f314406a0..bde619158 100644 --- a/src/posix/platform/system.cpp +++ b/src/posix/platform/system.cpp @@ -57,7 +57,7 @@ otInstance *otSysInit(otPlatformConfig *aPlatformConfig) #endif VerifyOrDie(args.GetPath() != nullptr, OT_EXIT_INVALID_ARGUMENTS); - platformAlarmInit(aPlatformConfig->mSpeedUpFactor); + platformAlarmInit(aPlatformConfig->mSpeedUpFactor, aPlatformConfig->mRealTimeSignal); platformRadioInit(&args); platformRandomInit(); diff --git a/tests/scripts/thread-cert/node.py b/tests/scripts/thread-cert/node.py index 6aab83093..8df2b38f7 100755 --- a/tests/scripts/thread-cert/node.py +++ b/tests/scripts/thread-cert/node.py @@ -108,7 +108,7 @@ class Node: cmd = '%s/examples/apps/cli/ot-cli-%s' % (srcdir, mode) if 'RADIO_DEVICE' in os.environ: - cmd += ' -v spinel+hdlc+uart://%s?forkpty-arg=%d' % ( + cmd += ' --real-time-signal=+1 -v spinel+hdlc+uart://%s?forkpty-arg=%d' % ( os.environ['RADIO_DEVICE'], nodeid) else: cmd += ' %d' % nodeid @@ -123,7 +123,7 @@ class Node: cmd = '%s/examples/apps/cli/ot-cli-%s' % (srcdir, mode) if 'RADIO_DEVICE_1_1' in os.environ: - cmd += ' -v spinel+hdlc+uart://%s?forkpty-arg=%d' % ( + cmd += ' --real-time-signal=+1 -v spinel+hdlc+uart://%s?forkpty-arg=%d' % ( os.environ['RADIO_DEVICE_1_1'], nodeid) else: cmd += ' %d' % nodeid @@ -151,7 +151,7 @@ class Node: # If Thread version of node matches the testing environment version. if self.version == self.env_version: if 'RADIO_DEVICE' in os.environ: - args = ' spinel+hdlc+uart://%s?forkpty-arg=%d' % ( + args = ' --real-time-signal=+1 spinel+hdlc+uart://%s?forkpty-arg=%d' % ( os.environ['RADIO_DEVICE'], nodeid) else: args = '' @@ -190,7 +190,7 @@ class Node: # Load Thread 1.1 node when testing Thread 1.2 scenarios for interoperability. elif self.version == '1.1': if 'RADIO_DEVICE_1_1' in os.environ: - args = ' spinel+hdlc+uart://%s?forkpty-arg=%d' % ( + args = ' --real-time-signal=+1 spinel+hdlc+uart://%s?forkpty-arg=%d' % ( os.environ['RADIO_DEVICE_1_1'], nodeid) else: args = ''