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]; }
|