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