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 : }
|