From ff3033f24f6b02d08bf33812600774d5860b9345 Mon Sep 17 00:00:00 2001 From: Yakun Xu Date: Tue, 25 Feb 2020 12:58:34 +0800 Subject: [PATCH] [posix-host] die on RCP timeout (#4591) When RCP fails to respond in time, it usually means RCP is stuck or in some bad situations that can only recover by hardware resetting. This commit changes the behavior on RCP timeout so that RCP can be reset during the host daemon restarting. --- src/posix/platform/hdlc_interface.cpp | 11 ++++--- .../include/openthread/openthread-system.h | 5 +++ src/posix/platform/misc.cpp | 4 +++ src/posix/platform/radio_spinel.cpp | 32 +++++++------------ 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/posix/platform/hdlc_interface.cpp b/src/posix/platform/hdlc_interface.cpp index 64183dd1d..96ae4cfe6 100644 --- a/src/posix/platform/hdlc_interface.cpp +++ b/src/posix/platform/hdlc_interface.cpp @@ -250,13 +250,12 @@ exit: otError HdlcInterface::WaitForFrame(const struct timeval &aTimeout) { - otError error = OT_ERROR_NONE; - struct timeval timeout = aTimeout; - + otError error = OT_ERROR_NONE; #if OPENTHREAD_POSIX_VIRTUAL_TIME struct Event event; + uint64_t delay = static_cast(aTimeout.tv_sec) * US_PER_S + static_cast(aTimeout.tv_usec); - virtualTimeSendSleepEvent(&timeout); + virtualTimeSendSleepEvent(&aTimeout); virtualTimeReceiveEvent(&event); switch (event.mEvent) @@ -266,7 +265,7 @@ otError HdlcInterface::WaitForFrame(const struct timeval &aTimeout) break; case OT_SIM_EVENT_ALARM_FIRED: - ExitNow(error = OT_ERROR_RESPONSE_TIMEOUT); + VerifyOrExit(event.mDelay <= delay, error = OT_ERROR_RESPONSE_TIMEOUT); break; default: @@ -274,6 +273,8 @@ otError HdlcInterface::WaitForFrame(const struct timeval &aTimeout) break; } #else // OPENTHREAD_POSIX_VIRTUAL_TIME + struct timeval timeout = aTimeout; + fd_set read_fds; fd_set error_fds; int rval; diff --git a/src/posix/platform/include/openthread/openthread-system.h b/src/posix/platform/include/openthread/openthread-system.h index e582cbfe3..476940563 100644 --- a/src/posix/platform/include/openthread/openthread-system.h +++ b/src/posix/platform/include/openthread/openthread-system.h @@ -82,6 +82,11 @@ enum * System call or library function error. */ OT_EXIT_ERROR_ERRNO = 5, + + /** + * No response from radio spinel. + */ + OT_EXIT_RADIO_SPINEL_NO_RESPONSE = 6, }; /** diff --git a/src/posix/platform/misc.cpp b/src/posix/platform/misc.cpp index e26e96eec..a5cd1da65 100644 --- a/src/posix/platform/misc.cpp +++ b/src/posix/platform/misc.cpp @@ -133,6 +133,10 @@ const char *otExitCodeToString(uint8_t aExitCode) retval = "RadioSpinelReset"; break; + case OT_EXIT_RADIO_SPINEL_NO_RESPONSE: + retval = "RadioSpinelNoResponse"; + break; + case OT_EXIT_ERROR_ERRNO: retval = strerror(errno); break; diff --git a/src/posix/platform/radio_spinel.cpp b/src/posix/platform/radio_spinel.cpp index c49d26b38..5673f6c68 100644 --- a/src/posix/platform/radio_spinel.cpp +++ b/src/posix/platform/radio_spinel.cpp @@ -1237,36 +1237,26 @@ otError RadioSpinel::Remove(spinel_prop_key_t aKey, const char *aFormat, ...) otError RadioSpinel::WaitResponse(void) { - uint64_t now = platformGetTime(); - uint64_t end = now + kMaxWaitTime * US_PER_MS; - struct timeval timeout = {kMaxWaitTime / 1000, (kMaxWaitTime % 1000) * 1000}; + uint64_t end = platformGetTime() + kMaxWaitTime * US_PER_MS; + + otLogInfoPlat("Wait response: tid=%u key=%u", mWaitingTid, mWaitingKey); do { - if (mSpinelInterface.WaitForFrame(timeout) == OT_ERROR_RESPONSE_TIMEOUT) - { - FreeTid(mWaitingTid); - mWaitingTid = 0; - ExitNow(mError = OT_ERROR_RESPONSE_TIMEOUT); - } + uint64_t now; + uint64_t remain; + struct timeval timeout; now = platformGetTime(); + VerifyOrDie(end > now, OT_EXIT_RADIO_SPINEL_NO_RESPONSE); + remain = end - now; - if (end > now) - { - uint64_t remain = end - now; + timeout.tv_sec = static_cast(remain / US_PER_S); + timeout.tv_usec = static_cast(remain % US_PER_S); - timeout.tv_sec = static_cast(remain / US_PER_S); - timeout.tv_usec = static_cast(remain % US_PER_S); - } - else - { - mWaitingTid = 0; - mError = OT_ERROR_RESPONSE_TIMEOUT; - } + VerifyOrDie(mSpinelInterface.WaitForFrame(timeout) == OT_ERROR_NONE, OT_EXIT_RADIO_SPINEL_NO_RESPONSE); } while (mWaitingTid || !mIsReady); -exit: LogIfFail("Error waiting response", mError); // This indicates end of waiting repsonse. mWaitingKey = SPINEL_PROP_LAST_STATUS;