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 "atrace_client_thread.h"
12 : #include "adiag_print.h"
13 : #include "trace_system_api.h"
14 : #include "adiag_lock.h"
15 : #include "adiag_utils.h"
16 :
17 : typedef struct {
18 : TraceThread tid;
19 : int32_t pid;
20 : int8_t threadStatus;
21 : TraceThreadArgs args;
22 : TraceUserBlock block;
23 : } ThreadInfo;
24 :
25 : STATIC ThreadInfo **g_traceThread = NULL;
26 : STATIC pthread_mutex_t g_traceThreadMutex = TRACE_MUTEX_INITIALIZER;
27 :
28 : /**
29 : * @brief : init thread mutex
30 : * @return : NA
31 : */
32 901 : STATIC INLINE void AtraceThreadMutexInit(void)
33 : {
34 901 : (void)AdiagLockInit(&g_traceThreadMutex);
35 901 : }
36 :
37 : /**
38 : * @brief : Destroy thread mutex
39 : * @return : NA
40 : */
41 951 : STATIC INLINE void AtraceThreadMutexDestroy(void)
42 : {
43 951 : (void)AdiagLockDestroy(&g_traceThreadMutex);
44 951 : }
45 :
46 : /**
47 : * @brief : lock thread mutex
48 : * @return : NA
49 : */
50 1966188 : STATIC INLINE void AtraceThreadLock(void)
51 : {
52 1966188 : (void)AdiagLockGet(&g_traceThreadMutex);
53 1966188 : }
54 :
55 : /**
56 : * @brief : unlock thread mutex
57 : * @return : NA
58 : */
59 1966188 : STATIC INLINE void AtraceThreadUnLock(void)
60 : {
61 1966188 : (void)AdiagLockRelease(&g_traceThreadMutex);
62 1966188 : }
63 :
64 400 : STATIC void AtraceThreadSetStatus(int32_t devId, int8_t value)
65 : {
66 400 : AtraceThreadLock();
67 400 : if ((g_traceThread != NULL) && (g_traceThread[devId] != NULL)) {
68 400 : g_traceThread[devId]->threadStatus = value;
69 : }
70 400 : AtraceThreadUnLock();
71 400 : }
72 :
73 16740 : int8_t AtraceThreadGetStatus(int32_t devId)
74 : {
75 16740 : int8_t status = THREAD_STATUS_INIT;
76 16740 : AtraceThreadLock();
77 16740 : if ((g_traceThread != NULL) && (g_traceThread[devId] != NULL)) {
78 16740 : status = g_traceThread[devId]->threadStatus;
79 : }
80 16740 : AtraceThreadUnLock();
81 16740 : return status;
82 : }
83 :
84 : /**
85 : * @brief : get tid of thread, make sure thread exist before callback
86 : * @param [in] : devId device id
87 : * @return : tid
88 : */
89 200 : STATIC TraceThread AtraceThreadGetTid(int32_t devId)
90 : {
91 200 : ADIAG_CHK_EXPR_ACTION((devId < 0) || (devId >= HOST_MAX_DEV_NUM), return (TraceThread)0,
92 : "can not get tid, invalid devId=%d.", devId);
93 200 : TraceThread tid = 0;
94 200 : AtraceThreadLock();
95 200 : if ((g_traceThread != NULL) && (g_traceThread[devId] != NULL)) {
96 200 : tid = g_traceThread[devId]->tid;
97 : }
98 200 : AtraceThreadUnLock();
99 200 : return tid;
100 : }
101 :
102 :
103 : /**
104 : * @brief : check thread existence or non-existence
105 : * @param [in] : devId device id
106 : * @return : true existence; false non-existence
107 : */
108 1948248 : STATIC bool AtraceThreadCheckExist(int32_t devId)
109 : {
110 1948248 : ADIAG_CHK_EXPR_ACTION((devId < 0) || (devId >= HOST_MAX_DEV_NUM), return false,
111 : "can not check thread, invalid devId=%d.", devId);
112 1948248 : AtraceThreadLock();
113 1948248 : if ((g_traceThread != NULL) && (g_traceThread[devId] != NULL) && (g_traceThread[devId]->tid != 0)) {
114 220 : AtraceThreadUnLock();
115 220 : return true;
116 : }
117 1948028 : AtraceThreadUnLock();
118 1948028 : return false;
119 : }
120 :
121 : /**
122 : * @brief : free threadInfo pointer, which malloc when create thread
123 : * @param [in] : devId device id
124 : * @return : NA
125 : */
126 200 : void AtraceThreadFree(int32_t devId)
127 : {
128 200 : ADIAG_CHK_EXPR_ACTION((devId < 0) || (devId >= HOST_MAX_DEV_NUM), return,
129 : "can not free atrace receive thread, invalid devId=%d.", devId);
130 200 : AtraceThreadLock();
131 200 : if ((g_traceThread != NULL) && (g_traceThread[devId] != NULL)) {
132 200 : AdiagFree(g_traceThread[devId]);
133 200 : g_traceThread[devId] = NULL;
134 : }
135 200 : AtraceThreadUnLock();
136 : }
137 :
138 : /**
139 : * @brief : check current pid is same to previous pid(when create thread)
140 : * @param [in] : devId device id
141 : * @return : true same; false different
142 : */
143 200 : STATIC bool AtraceThreadCheckPid(int32_t devId)
144 : {
145 200 : ADIAG_CHK_EXPR_ACTION((devId < 0) || (devId >= HOST_MAX_DEV_NUM), return false,
146 : "can not get tid, invalid devId=%d.", devId);
147 200 : bool ret = true;
148 200 : AtraceThreadLock();
149 200 : if ((g_traceThread != NULL) && (g_traceThread[devId] != NULL)) {
150 200 : ret = (g_traceThread[devId]->pid == TraceGetPid()) ? true : false;
151 : }
152 200 : AtraceThreadUnLock();
153 200 : return ret;
154 : }
155 : /**
156 : * @brief : join thread to release thread resource, then free ThreadInfo
157 : * @param [in] : devId device id
158 : */
159 200 : STATIC void AtraceThreadJoinTask(int32_t devId)
160 : {
161 200 : TraceThread tid = AtraceThreadGetTid(devId);
162 200 : if ((tid > (TraceThread)0) && (AtraceThreadCheckPid(devId))) {
163 200 : int32_t ret = TraceJoinTask(&tid);
164 200 : if (ret != 0) {
165 0 : ADIAG_WAR("can not join atrace receive thread, devId=%d, strerr=%s.", devId, strerror(AdiagGetErrorCode()));
166 : }
167 : }
168 200 : AtraceThreadFree(devId);
169 200 : }
170 :
171 : /**
172 : * @brief : make sure single thread for one device
173 : * @param [in] : devId device id
174 : * @return : true single thread; false no thread
175 : */
176 220 : bool AtraceThreadSingleTask(int32_t devId)
177 : {
178 220 : if (AtraceThreadCheckExist(devId) == false) {
179 220 : return false;
180 : }
181 0 : if (AtraceThreadGetStatus(devId) == THREAD_STATUS_WAIT_EXIT) {
182 0 : AtraceThreadJoinTask(devId);
183 0 : return false;
184 : }
185 0 : return true;
186 : }
187 :
188 : /**
189 : * @brief : create thread for receive device log
190 : * @param [in] : devId device id
191 : * @param [in] : pArgs pointer of thread args
192 : * @param [in] : func thread run function
193 : * @return : !=0 failure; ==0 success
194 : */
195 200 : TraStatus AtraceThreadCreate(int32_t devId, TraceThreadArgs *pArgs, ThreadRunFunc func)
196 : {
197 200 : ADIAG_CHK_EXPR_ACTION(g_traceThread == NULL, return TRACE_FAILURE,
198 : "create thread failed, thread pool is not initialized.");
199 200 : ADIAG_CHK_EXPR_ACTION((devId < 0) || (devId >= HOST_MAX_DEV_NUM), return TRACE_FAILURE,
200 : "create thread failed, invalid devId=%d.", devId);
201 200 : ADIAG_CHK_EXPR_ACTION(pArgs == NULL, return TRACE_FAILURE,
202 : "create thread failed, thread args is null.");
203 200 : ADIAG_CHK_EXPR_ACTION(AtraceThreadCheckExist(devId), return TRACE_FAILURE,
204 : "log receive thread has bean started, devId=%d.", devId);
205 :
206 200 : ThreadInfo *pThread = (ThreadInfo *)AdiagMalloc(sizeof(ThreadInfo));
207 200 : ADIAG_CHK_EXPR_ACTION(pThread == NULL, return TRACE_FAILURE, "malloc failed, can not create atrace receive thread");
208 :
209 200 : AtraceThreadLock();
210 200 : g_traceThread[devId] = pThread;
211 200 : int32_t ret = memcpy_s(&g_traceThread[devId]->args, sizeof(TraceThreadArgs), pArgs, sizeof(TraceThreadArgs));
212 200 : if (ret != EOK) {
213 0 : ADIAG_ERR("copy data failed, strerr=%s.", strerror(AdiagGetErrorCode()));
214 : }
215 :
216 200 : g_traceThread[devId]->pid = TraceGetPid();
217 200 : g_traceThread[devId]->block.procFunc = func;
218 200 : g_traceThread[devId]->block.pulArg = (void *)(&g_traceThread[devId]->args);
219 200 : TraceThreadAttr threadAttr = { 0, 0, 0, 0, 0, 0, 128 * 1024 }; // joinable
220 200 : ret = TraceCreateTaskWithThreadAttr(&g_traceThread[devId]->tid, &g_traceThread[devId]->block, &threadAttr);
221 200 : AtraceThreadUnLock();
222 200 : if (ret != TRACE_SUCCESS) {
223 0 : AtraceThreadFree(devId);
224 0 : return TRACE_FAILURE;
225 : }
226 200 : AtraceThreadSetStatus(devId, THREAD_STATUS_RUN);
227 200 : return TRACE_SUCCESS;
228 : }
229 :
230 : /**
231 : * @brief : release single thread
232 : * @param [in] : devId device id
233 : * @param [in] : func thread stop function
234 : * @param [in] : sync whether to wait thread exit
235 : * @return : NA
236 : */
237 974004 : void AtraceThreadRelease(int32_t devId, ThreadStopFunc func, bool sync)
238 : {
239 974004 : if (AtraceThreadCheckExist(devId) == true) {
240 200 : if ((func != NULL) && (AtraceThreadGetStatus(devId) != THREAD_STATUS_WAIT_EXIT)) {
241 200 : func(devId);
242 200 : AtraceThreadSetStatus(devId, THREAD_STATUS_WAIT_EXIT);
243 : }
244 200 : if (sync == true) {
245 180 : AtraceThreadJoinTask(devId);
246 : }
247 : }
248 974004 : }
249 :
250 : /**
251 : * @brief : init thread pool
252 : * @return : NA
253 : */
254 901 : TraStatus AtraceThreadPoolInit(void)
255 : {
256 901 : g_traceThread = (ThreadInfo **)AdiagMalloc((size_t)HOST_MAX_DEV_NUM * sizeof(ThreadInfo *));
257 901 : ADIAG_CHK_EXPR_ACTION(g_traceThread == NULL, return TRACE_FAILURE, "malloc thread pool failed.");
258 901 : AtraceThreadMutexInit();
259 901 : return TRACE_SUCCESS;
260 : }
261 :
262 : /**
263 : * @brief : exit thread pool
264 : * @param [in] : func thread stop function
265 : * @return : NA
266 : */
267 951 : void AtraceThreadPoolExit(ThreadStopFunc func)
268 : {
269 : int32_t i;
270 974775 : for (i = 0; i < HOST_MAX_DEV_NUM; i++) {
271 973824 : AtraceThreadRelease(i, func, false);
272 : }
273 : // wait all thread exit after stop them, to improve running efficiency
274 974775 : for (i = 0; i < HOST_MAX_DEV_NUM; i++) {
275 973824 : if (AtraceThreadCheckExist(i) == true) {
276 20 : AtraceThreadJoinTask(i);
277 : }
278 : }
279 951 : AdiagFree(g_traceThread);
280 951 : g_traceThread = NULL;
281 951 : AtraceThreadMutexDestroy();
282 951 : }
|