最近在調查一個,相機在使用過程中,相機莫名奇妙報申請預覽超時的問題,
報的錯誤如下:
camxsession.cpp:1269 ProcessCaptureRequest() Lets do a Reset
camxchi.cpp:588 ChiSubmitPipelineRequest() Submit request failed with error 9.
本來以爲是CPU使用過高,導致預覽上報超時,然後各種分析性能功耗。進入了一個更大的坑,無法自拔!!!
最近找到了復現規律,只要修改下系統時間,都會報上述錯誤!!!天坑啊!!!
於是仔細研究了下camx的代碼,在不經意間,把鎖的源碼打開看看了,發現了這個天坑的原因(天啊,誰會想到,鎖的實現竟然存在問題!!)
代碼如下:
CamxResult Condition::TimedWait(
OSMutexHandle* phMutex,
UINT timeoutMilliseconds)
{
CamxResult result = CamxResultSuccess;
INT waitResult = 0;
UINT timeoutSeconds = (timeoutMilliseconds / 1000UL);
UINT timeoutNanoseconds = (timeoutMilliseconds % 1000UL) * 1000000UL;
struct timespec timeout = {0};
// Calculate the timeout time
//通過CLOCK_REALTIME獲取的時間是受系統時間影響的!!!
clock_gettime(CLOCK_REALTIME, &timeout);
timeoutSeconds += (static_cast<UINT>(timeout.tv_nsec) + timeoutNanoseconds) / 1000000000UL;
timeoutNanoseconds = (static_cast<UINT>(timeout.tv_nsec) + timeoutNanoseconds) % 1000000000UL;
timeout.tv_sec += static_cast<INT>(timeoutSeconds);
timeout.tv_nsec = static_cast<INT>(timeoutNanoseconds);
//如果在pthread_cond_timedwait的過程中,系統時間突然變大,這個鎖直接返回CamxResultETimeout
waitResult = pthread_cond_timedwait(&m_conditionVar, phMutex, &timeout);
if (waitResult != 0)
{
// Check errno for reason for failure
if (ETIMEDOUT == waitResult)
{
result = CamxResultETimeout;
}
else
{
result = CamxResultEFailed;
}
}
return result;
}
百度了下,說是將CLOCK_REALTIME改爲CLOCK_MONOTONIC再獲取的時間就可以不受系統時間影響。
修改後,發現還是不生效,本來是偶現的問題,成了必現問題!!!!
今天在萬能的CSDN中,閱讀了一篇大牛文章:
“pthread_cond_timedwait按相對時間等待超時完整示例代碼”
https://blog.csdn.net/yichigo/article/details/23459613
按照文章的實現,完美解決了該問題
@@ -1741,7 +1741,9 @@ CamxResult Condition::Initialize(
m_pResource = pResource;
- if (pthread_cond_init(&m_conditionVar, NULL) == 0)
+ pthread_condattr_setclock(&m_cattr, CLOCK_MONOTONIC);
+
+ if (pthread_cond_init(&m_conditionVar, &m_cattr) == 0)
{
m_validConditionVar = TRUE;
}
@@ -1795,7 +1797,7 @@ CamxResult Condition::TimedWait(
struct timespec timeout = {0};
// Calculate the timeout time
- clock_gettime(CLOCK_REALTIME, &timeout);
+ clock_gettime(CLOCK_MONOTONIC, &timeout);