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

Generated by: LCOV version 2.0-1