LCOV - code coverage report
Current view: top level - awatchdog - awatchdog_core.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 85.1 % 101 86
Test Date: 2026-07-28 10:53:44 Functions: 100.0 % 12 12

            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              : 
      11              : #include "awatchdog_core.h"
      12              : #include "adiag_print.h"
      13              : #include "adiag_utils.h"
      14              : #include "awatchdog_monitor.h"
      15              : #include "ascend_hal.h"
      16              : 
      17              : #define DRIVER_GET_PLATFORM_INFO_API "drvGetPlatformInfo"
      18              : #define DRIVER_LIBRARY_NAME "libascend_hal.so"
      19              : #define DRIVER_PLATFORM_DEVICE_SIDE 0
      20              : #define DRIVER_PLATFORM_HOST_SIDE 1
      21              : 
      22              : static AwdWatchdogMgr g_awdWatchdogMgr = {0};
      23              : static bool g_forking = false;
      24              : typedef void (*ThreadAtFork)(void);
      25              : 
      26            5 : STATIC void AwdGetAllLock(void)
      27              : {
      28           10 :     for (int32_t i = 0; i < (int32_t)AWD_WATCHDOG_TYPE_MAX; i++) {
      29            5 :         (void)AdiagLockGet(&g_awdWatchdogMgr.awd[i].runList.lock);
      30            5 :         (void)AdiagLockGet(&g_awdWatchdogMgr.awd[i].newList.lock);
      31              :     }
      32            5 : }
      33              : 
      34            5 : STATIC void AwdReleaseAllLock(void)
      35              : {
      36           10 :     for (int32_t i = 0; i < (int32_t)AWD_WATCHDOG_TYPE_MAX; i++) {
      37            5 :         (void)AdiagLockRelease(&g_awdWatchdogMgr.awd[i].runList.lock);
      38            5 :         (void)AdiagLockRelease(&g_awdWatchdogMgr.awd[i].newList.lock);
      39              :     }
      40            5 : }
      41              : 
      42            2 : STATIC void AwdSubProcessInit(void)
      43              : {
      44            2 :     ADIAG_DBG("[fork] watchdog subprocess init");
      45            2 :     if (!g_forking) {
      46              :         // sub process has been initialized
      47            0 :         return;
      48              :     }
      49            2 :     AwdMonitorReset();  // reset thread id
      50            2 :     g_awdWatchdogMgr.monitorStarted = false;  // set monitorStarted to false to restart monitor thread when create
      51            2 :     AwdReleaseAllLock();
      52            2 :     g_forking = false;
      53              : }
      54              : 
      55            5 : STATIC void AwdProcessUnInit(void)
      56              : {
      57            5 :     g_forking = true; // set forking to true to avoid repeat uninit and init
      58            5 :     ADIAG_DBG("[fork] watchdog process uninit");
      59            5 :     AwdGetAllLock();
      60            5 : }
      61              : 
      62            3 : STATIC void AwdProcessInit(void)
      63              : {
      64            3 :     ADIAG_DBG("[fork] watchdog process init");
      65            3 :     AwdReleaseAllLock();
      66            3 :     g_forking = false;
      67            3 : }
      68              : 
      69           19 : STATIC void AwdPrepareForFork(void)
      70              : {
      71           19 :     int32_t ret = pthread_atfork((ThreadAtFork)AwdProcessUnInit, (ThreadAtFork)AwdProcessInit,
      72              :         (ThreadAtFork)AwdSubProcessInit);
      73           19 :     if (ret != 0) {
      74            0 :         ADIAG_WAR("can not call pthread_atfork, ret=%d", ret);
      75              :     }
      76           19 : }
      77              : 
      78              : typedef drvError_t (*DrvGetPlatformInfo)(uint32_t *);
      79           19 : STATIC bool AwdCheckIsOnDeviceSide(void)
      80              : {
      81           19 :     void *handle = mmDlopen(DRIVER_LIBRARY_NAME, RTLD_LAZY);
      82           19 :     if (handle == NULL) {
      83            0 :         ADIAG_WAR("can not dlopen lib %s, reason:%s", DRIVER_LIBRARY_NAME, strerror(errno));
      84            0 :         return false;
      85              :     }
      86           19 :     void* getPlatFormInfoFunc = mmDlsym(handle, DRIVER_GET_PLATFORM_INFO_API);
      87           19 :     if (getPlatFormInfoFunc == NULL) {
      88            0 :         ADIAG_WAR("can not find symbol %s in %s.", DRIVER_GET_PLATFORM_INFO_API, DRIVER_LIBRARY_NAME);
      89            0 :         (void)mmDlclose(handle);
      90            0 :         return false;
      91              :     }
      92           19 :     uint32_t platform = DRIVER_PLATFORM_HOST_SIDE;
      93           19 :     drvError_t ret = ((DrvGetPlatformInfo)getPlatFormInfoFunc)(&platform);
      94           19 :     if (ret == DRV_ERROR_NONE && platform == DRIVER_PLATFORM_DEVICE_SIDE) {
      95            0 :         ADIAG_INF("watchdog get platform device side");
      96            0 :         (void)mmDlclose(handle);
      97            0 :         return true;
      98              :     }
      99           19 :     ADIAG_INF("watchdog get platform host side");
     100           19 :     (void)mmDlclose(handle);
     101           19 :     return false;
     102              : }
     103              : 
     104           19 : STATIC bool AwdCheckFeatureEnable(void)
     105              : {
     106           19 :     if (!AwdCheckIsOnDeviceSide()) {
     107           19 :         return true;
     108              :     }
     109            0 :     return false;
     110              : }
     111              : 
     112           19 : STATIC CONSTRUCTOR void AwatchdogInit(void)
     113              : {
     114           19 :     g_awdWatchdogMgr.enable = AwdCheckFeatureEnable();
     115           19 :     if (!g_awdWatchdogMgr.enable) {
     116            0 :         ADIAG_WAR("watchdog is not enable on current platform");
     117            0 :         return;
     118              :     }
     119           38 :     for (int32_t i = 0; i < (int32_t)AWD_WATCHDOG_TYPE_MAX; i++) {
     120           19 :         (void)AdiagListInit(&g_awdWatchdogMgr.awd[i].runList);
     121           19 :         (void)AdiagListInit(&g_awdWatchdogMgr.awd[i].newList);
     122              :     }
     123           19 :     g_awdWatchdogMgr.monitorStarted = false;
     124           19 :     AwdPrepareForFork();
     125              : }
     126              : 
     127           17 : STATIC DESTRUCTOR void AwatchdogExit(void)
     128              : {
     129           17 :     if (!g_awdWatchdogMgr.enable) {
     130            0 :         return;
     131              :     }
     132           17 :     AwdMonitorExit();
     133           17 :     g_awdWatchdogMgr.monitorStarted = false;
     134           34 :     for (int32_t i = 0; i < (int32_t)AWD_WATCHDOG_TYPE_MAX; i++) {
     135           17 :         (void)AdiagListDestroy(&g_awdWatchdogMgr.awd[i].runList);
     136           17 :         (void)AdiagListDestroy(&g_awdWatchdogMgr.awd[i].newList);
     137              :     }
     138              : }
     139              : 
     140              : /**
     141              :  * @brief       Create watchdog handle.
     142              :  * @param [in]  dogId:         dog id get from DEFINE_THREAD_WATCHDOG_ID(moduleId)
     143              :  * @param [in]  timeout:       timeout, s
     144              :  * @param [in]  callback:      callback function
     145              :  * @param [in]  type:          watchdog type
     146              :  * @return      atrace handle
     147              :  */
     148           16 : AwdThreadWatchdog* AwdWatchdogCreate(uint32_t dogId, uint32_t timeout, AwatchdogCallbackFunc callback,
     149              :     enum AwdWatchdogType type)
     150              : {
     151           16 :     if (!g_awdWatchdogMgr.enable) {
     152            0 :         return NULL;
     153              :     }
     154           16 :     if (g_awdWatchdogMgr.monitorStarted == false) {
     155              :         // judge initialized first to avoid using atomic operations every time
     156           15 :         if (AWD_ATOMIC_CMP_AND_SWAP(&g_awdWatchdogMgr.monitorStarted, false,  true)) {
     157              :             /* Prevent duplicate initialization.
     158              :                Dog create may finished before monitor thread start, but timeout must be more than 1s.
     159              :                When watchdog timeout, monitor thread must have been started, so ignored. */
     160           15 :             AwdStatus ret = AwdMonitorInit();
     161           15 :             if (ret != AWD_SUCCESS) {
     162              :                 /* Conditionally reset: only if we still hold the init right (monitorStarted == true).
     163              :                    This avoids overwriting a concurrent thread's successful init. */
     164            1 :                 (void)AWD_ATOMIC_CMP_AND_SWAP(&g_awdWatchdogMgr.monitorStarted, true, false);
     165              :             }
     166              :         }
     167              :     }
     168           16 :     AwdThreadWatchdog *dog = (AwdThreadWatchdog *)AdiagMalloc(sizeof(AwdThreadWatchdog));
     169           16 :     if (dog == NULL) {
     170            3 :         return NULL;
     171              :     }
     172           13 :     dog->tid = (int32_t)syscall(SYS_gettid);
     173           13 :     dog->pid = (int32_t)getpid();
     174           13 :     dog->dogId = dogId;
     175           13 :     dog->timeout = timeout;
     176           13 :     dog->callback = callback;
     177           13 :     AWD_ATOMIC_TEST_AND_SET(&dog->runCount, 0);
     178           13 :     AWD_ATOMIC_TEST_AND_SET(&dog->startCount, AWD_STATUS_INIT);
     179           13 :     ADIAG_INF("create watchdog for id : %u, tid : %d, timeout : %us", dog->dogId, dog->tid, timeout);
     180              :     // add to list after node init finished
     181           13 :     AwdStatus ret = AdiagListInsert(&(g_awdWatchdogMgr.awd[type].newList), (void *)dog);
     182           13 :     if (ret != ADIAG_SUCCESS) {
     183            3 :         ADIAG_SAFE_FREE(dog);
     184            3 :         ADIAG_ERR("add watchdog node for module : %u to new list failed", dogId);
     185            3 :         return NULL;
     186              :     }
     187           10 :     return dog;
     188              : }
     189              : 
     190              : /**
     191              :  * @brief       Get watchdog manager ptr by type
     192              :  * @param [in]  type:   watchdog type
     193              :  * @return      watchdog manager ptr
     194              :  */
     195            6 : struct AwdWatchDog* AwdGetWatchDog(enum AwdWatchdogType type)
     196              : {
     197            6 :     return &g_awdWatchdogMgr.awd[type];
     198              : }
        

Generated by: LCOV version 2.0-1