LCOV - code coverage report
Current view: top level - awatchdog - awatchdog_monitor.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 74.2 % 124 92
Test Date: 2026-08-12 11:04:46 Functions: 92.9 % 14 13

            Line data    Source code
       1              : /**
       2              :  * Copyright (c) 2025 Huawei Technologies Co., Ltd.
       3              :  * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
       4              :  * CANN Open Software License Agreement Version 2.0 (the "License").
       5              :  * Please refer to the License for details. You may not use this file except in compliance with the License.
       6              :  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
       7              :  * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
       8              :  * See LICENSE in the root of the software repository for the full text of the License.
       9              :  */
      10              : #include "awatchdog_monitor.h"
      11              : #include "adiag_list.h"
      12              : #include "adiag_print.h"
      13              : #include "adiag_utils.h"
      14              : #include "awatchdog.h"
      15              : #include "awatchdog_core.h"
      16              : #include "mmpa_api.h"
      17              : 
      18              : #define MAX_TIMEOUT_COUNT 0xFFFFFFF
      19              : #define AWD_DEFAULT_MONITOR_PERIOD 200000U // 200ms, must be smaller than 1s
      20              : #define MAX_THREAD_TASK_PATH_LENGTH 50U
      21              : #define ADIAG_NS_TO_US 1000U
      22              : #define ADIAG_US_TO_MS 1000U
      23              : #define ADIAG_MS_TO_S 1000U
      24              : #define AWD_THREAD_STACK_SIZE (128 * 1024)
      25              : 
      26              : typedef struct AwdMonitorInfo {
      27              :     uint32_t watchdogCount; // monitor loop count
      28              :     uint32_t watchdogPeriod; // watchdogCount * 最大公约数 <= watchdogPeriod,相等时,watchdogCount 归零,执行一次监控
      29              :     void (*watchdogFunc)(void);
      30              : } AwdMonitorInfo;
      31              : 
      32              : #define THREAD_STATUS_INIT 0
      33              : #define THREAD_STATUS_RUN 1
      34              : #define THREAD_STATUS_WAIT_EXIT 2
      35              : 
      36              : static AwdMonitorInfo g_awdMonitorInfo[AWD_WATCHDOG_TYPE_MAX] = {{0}};
      37              : static int32_t g_awdMonitorThreadStatus = THREAD_STATUS_INIT;
      38              : static uint32_t g_awdMonitorResPeriod = AWD_DEFAULT_MONITOR_PERIOD;
      39              : static mmThread g_awdMonitorThreadId = 0;
      40              : 
      41            1 : STATIC INLINE uint32_t AwdGetWatchDogModuleId(uint32_t dogId)
      42              : {
      43            1 :     return (dogId & (((uint32_t)1U << WATCHDOG_TYPE_BIT) - 1U));
      44              : }
      45              : 
      46              : // Maximum common divisor
      47            1 : STATIC INLINE uint32_t AwdMonitorGetCommonDivisor(uint32_t x, uint32_t y)
      48              : {
      49            1 :     uint32_t a = x;
      50            1 :     uint32_t b = y;
      51            1 :     while (a != b) {
      52            0 :         if (a > b) {
      53            0 :             a = a - b;
      54              :         } else {
      55            0 :             b = b - a;
      56              :         }
      57              :     }
      58            1 :     return a;
      59              : }
      60              : 
      61            1 : STATIC INLINE void AwdMonitorGetPeriod(void)
      62              : {
      63            1 :     uint32_t temp = g_awdMonitorInfo[0].watchdogPeriod;
      64            2 :     for (int32_t i = 0; i < (int32_t)AWD_WATCHDOG_TYPE_MAX; i++) {
      65            1 :         temp = AwdMonitorGetCommonDivisor(temp, g_awdMonitorInfo[i].watchdogPeriod);
      66            1 :         ADIAG_DBG("watchdog %d, period %u, resPeriod %u", i, g_awdMonitorInfo[i].watchdogPeriod, temp);
      67              :     }
      68            1 :     g_awdMonitorResPeriod = temp;
      69            1 : }
      70              : 
      71            0 : STATIC INLINE void AwdMonitorResItem(void)
      72              : {
      73            0 :     for (int32_t i = 0; i < (int32_t)AWD_WATCHDOG_TYPE_MAX; i++) {
      74            0 :         g_awdMonitorInfo[i].watchdogCount++;
      75            0 :         if (g_awdMonitorInfo[i].watchdogCount * g_awdMonitorResPeriod >= g_awdMonitorInfo[i].watchdogPeriod) {
      76            0 :             g_awdMonitorInfo[i].watchdogFunc();
      77            0 :             g_awdMonitorInfo[i].watchdogCount = 0;
      78              :         }
      79              :     }
      80            0 : }
      81              : 
      82            1 : STATIC void* AwdMonitorProcess(void* arg)
      83              : {
      84              :     (void)arg;
      85            1 :     AwdMonitorGetPeriod();
      86            1 :     const uint32_t period = g_awdMonitorResPeriod;
      87            1 :     uint64_t start = GetRealTime() / ADIAG_NS_TO_US;
      88              :     uint64_t end;
      89              :     uint32_t sleepTime;
      90            1 :     (void)mmSetCurrentThreadName("WatchdogMonitor");
      91            1 :     while (g_awdMonitorThreadStatus == THREAD_STATUS_RUN) {
      92            0 :         AwdMonitorResItem();
      93            0 :         end = GetRealTime() / ADIAG_NS_TO_US;
      94            0 :         uint32_t duration = (uint32_t)(end - start);
      95            0 :         if (duration >= period) {
      96              :             static bool warningFlag = true;
      97            0 :             if (warningFlag) {
      98            0 :                 ADIAG_WAR(
      99              :                     "awd monitor res period %uus is less than process duration %uus, may need to be increased", period,
     100              :                     duration);
     101            0 :                 warningFlag = false;
     102              :             }
     103            0 :             start = start + duration;
     104            0 :             continue;
     105              :         }
     106            0 :         sleepTime = period - duration;
     107            0 :         (void)usleep(sleepTime);
     108            0 :         start = start + sleepTime;
     109              :     }
     110            1 :     AwdWatchDog* awd = AwdGetWatchDog(AWD_WATCHDOG_TYPE_THREAD);
     111            1 :     (void)AdiagListDestroy(&awd->runList);
     112            1 :     (void)AdiagListDestroy(&awd->newList);
     113            1 :     return NULL;
     114              : }
     115              : 
     116            3 : STATIC INLINE AwdStatus AwdCreateMonitorThread(void)
     117              : {
     118              :     mmUserBlock_t thread;
     119            3 :     thread.procFunc = AwdMonitorProcess;
     120            3 :     thread.pulArg = NULL;
     121            3 :     mmThreadAttr attr = {0, 0, 0, 0, 0, 0, AWD_THREAD_STACK_SIZE};
     122            3 :     mmThread tid = 0;
     123            3 :     if (mmCreateTaskWithThreadAttr(&tid, &thread, &attr) != 0) {
     124            2 :         ADIAG_ERR("create task failed, strerr=%s.", strerror(errno));
     125            2 :         return AWD_FAILURE;
     126              :     }
     127            1 :     g_awdMonitorThreadId = tid;
     128            1 :     ADIAG_INF("create monitor thread successfully, tid :%ld ", tid);
     129            1 :     return AWD_SUCCESS;
     130              : }
     131              : 
     132            1 : STATIC INLINE bool CheckThreadExist(AwdThreadWatchdog* node)
     133              : {
     134            1 :     char dir[MAX_THREAD_TASK_PATH_LENGTH] = {0};
     135            1 :     int ret = sprintf_s(dir, MAX_THREAD_TASK_PATH_LENGTH, "/proc/%d/task/%d", node->pid, node->tid);
     136            1 :     if (ret == -1) {
     137            0 :         ADIAG_ERR("sprintf thread dir failed", strerror(errno));
     138            0 :         return true;
     139              :     }
     140            1 :     if (access(dir, F_OK) != 0) {
     141            0 :         return false;
     142              :     }
     143            1 :     return true;
     144              : }
     145              : 
     146            1 : STATIC void AwdProcessTimeout(AwdThreadWatchdog* node)
     147              : {
     148            1 :     AWD_ATOMIC_TEST_AND_SET(&node->startCount, AWD_STATUS_INIT);
     149              :     // record timeout log to run info
     150            1 :     ADIAG_RUN_INF("watchdog timeout, moduleId %u, timeout : %us", AwdGetWatchDogModuleId(node->dogId), node->timeout);
     151            1 :     if (node->callback != NULL) {
     152            1 :         node->callback(NULL);
     153              :     }
     154            1 : }
     155              : 
     156            1 : STATIC AdiagStatus AwdMonitorThreadWatchdogPro(void* data)
     157              : {
     158            1 :     AwdThreadWatchdog* node = (AwdThreadWatchdog*)data;
     159            1 :     int32_t startCount = node->startCount;
     160            1 :     if (!CheckThreadExist(node)) {
     161            0 :         ADIAG_DBG("thread %d does not exist", node->tid);
     162            0 :         AWD_ATOMIC_TEST_AND_SET(&node->startCount, AWD_STATUS_DESTROYED);
     163            0 :         return AWD_SUCCESS;
     164              :     }
     165            1 :     if (startCount == AWD_STATUS_INIT) {
     166            0 :         return AWD_SUCCESS;
     167              :     }
     168              :     // process runCount
     169            1 :     int32_t runCount = node->runCount + 1;
     170            1 :     if (runCount == MAX_TIMEOUT_COUNT) {
     171            0 :         runCount = 0;
     172              :     }
     173            1 :     AWD_ATOMIC_TEST_AND_SET(&node->runCount, runCount);
     174              :     // calculate duration time
     175              :     uint64_t duration;
     176            1 :     if (runCount < startCount) {
     177            0 :         duration = (uint64_t)runCount + (uint64_t)MAX_TIMEOUT_COUNT - (uint64_t)startCount;
     178              :     } else {
     179            1 :         duration = (uint64_t)runCount - (uint64_t)startCount;
     180              :     }
     181              :     // add 1 second to compensate the time of start
     182            1 :     duration = (duration + 1U) * (uint64_t)g_awdMonitorInfo[AWD_WATCHDOG_TYPE_THREAD].watchdogPeriod / ADIAG_US_TO_MS;
     183            1 :     if (duration / ADIAG_MS_TO_S >= node->timeout) {
     184            1 :         AwdProcessTimeout(node);
     185              :     }
     186            1 :     return AWD_SUCCESS;
     187              : }
     188              : 
     189            1 : STATIC INLINE AdiagStatus CheckNodeDestroyed(const void* nodeData, const void* data)
     190              : {
     191              :     (void)data;
     192            1 :     const AwdThreadWatchdog* dog = (const AwdThreadWatchdog*)nodeData;
     193            1 :     if (dog->startCount == AWD_STATUS_DESTROYED) {
     194            1 :         return ADIAG_SUCCESS;
     195              :     }
     196            0 :     return ADIAG_FAILURE;
     197              : }
     198              : 
     199            1 : STATIC INLINE void AwdMonitorThreadWatchdog(void)
     200              : {
     201            1 :     AwdWatchDog* awd = AwdGetWatchDog(AWD_WATCHDOG_TYPE_THREAD);
     202              :     // move watchdog node from newList to runList
     203            1 :     AdiagListMove(&awd->newList, &awd->runList);
     204              : 
     205            1 :     (void)AdiagListClearAndProcessNoLock(&awd->runList, CheckNodeDestroyed, NULL, AwdMonitorThreadWatchdogPro);
     206            1 : }
     207              : 
     208            4 : void AwdMonitorReset(void) { g_awdMonitorThreadStatus = THREAD_STATUS_WAIT_EXIT; }
     209              : 
     210            3 : AwdStatus AwdMonitorInit(void)
     211              : {
     212            3 :     g_awdMonitorInfo[AWD_WATCHDOG_TYPE_THREAD].watchdogPeriod = AWD_DEFAULT_MONITOR_PERIOD;
     213            3 :     g_awdMonitorInfo[AWD_WATCHDOG_TYPE_THREAD].watchdogCount = 0;
     214            3 :     g_awdMonitorInfo[AWD_WATCHDOG_TYPE_THREAD].watchdogFunc = AwdMonitorThreadWatchdog;
     215              : 
     216            3 :     g_awdMonitorThreadStatus = THREAD_STATUS_RUN;
     217            3 :     AwdStatus ret = AwdCreateMonitorThread();
     218            3 :     if (ret != AWD_SUCCESS) {
     219            2 :         g_awdMonitorThreadId = 0;
     220            2 :         g_awdMonitorThreadStatus = THREAD_STATUS_INIT;
     221            2 :         ADIAG_ERR("Create monitor thread failed");
     222            2 :         return AWD_FAILURE;
     223              :     }
     224            1 :     ADIAG_INF("AwdMonitorInit");
     225            1 :     return AWD_SUCCESS;
     226              : }
     227              : 
     228           20 : void AwdMonitorExit(void)
     229              : {
     230           20 :     if (g_awdMonitorThreadStatus != THREAD_STATUS_RUN) {
     231           19 :         return;
     232              :     }
     233            1 :     ADIAG_INF("AwdMonitorExit");
     234            1 :     g_awdMonitorThreadStatus = THREAD_STATUS_WAIT_EXIT;
     235            1 :     if (g_awdMonitorThreadId != 0) {
     236            1 :         (void)mmJoinTask(&g_awdMonitorThreadId);
     237            1 :         g_awdMonitorThreadId = 0;
     238              :     }
     239              : }
        

Generated by: LCOV version 2.0-1