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 : #include "stacktrace_monitor.h"
11 : #include "stacktrace_unwind.h"
12 : #include "adiag_print.h"
13 : #include "mmpa_api.h"
14 : typedef void (*ThreadAtFork)(void);
15 :
16 : #define STACKTRACE_SLEEP_PERIOD 100000U // 100ms
17 : #define STACKTRACE_UPDATE_PERIOD 100U // 0.1s * 100 = 10s
18 : #define STACKTRACE_THREAD_STACK_SIZE 128 * 1024
19 : #define THREAD_STATUS_INIT 0
20 : #define THREAD_STATUS_RUN 1
21 : #define THREAD_STATUS_WAIT_EXIT 2
22 :
23 : #define STACKTRACE_UPDATE_STATUS_INIT 0U
24 : #define STACKTRACE_UPDATE_STATUS_START 1U
25 : #define STACKTRACE_UPDATE_STATUS_FINISH 2U
26 :
27 : static int32_t g_stacktraceMonitorThreadStatus = THREAD_STATUS_INIT;
28 :
29 : static mmThread g_stacktraceMonitorPthreadId = 0;
30 : static pid_t g_stacktraceMonitorthreadId = 0;
31 : static uint32_t g_stacktraceUpdateStatus;
32 : static bool g_forking = false;
33 : STATIC pthread_mutex_t g_forkMutex = PTHREAD_MUTEX_INITIALIZER;
34 :
35 :
36 80 : void StacktraceMonitorStartUpdate(void)
37 : {
38 80 : g_stacktraceUpdateStatus = STACKTRACE_UPDATE_STATUS_START;
39 80 : }
40 :
41 0 : pid_t StacktraceMonitorGetTid(void)
42 : {
43 0 : return g_stacktraceMonitorthreadId;
44 : }
45 :
46 0 : bool StacktraceCheckUpdateFinished(void)
47 : {
48 0 : return (g_stacktraceUpdateStatus == STACKTRACE_UPDATE_STATUS_FINISH);
49 : }
50 :
51 903 : static void *StacktraceMonitorProcess(void *arg)
52 : {
53 : (void)arg;
54 903 : g_stacktraceMonitorthreadId = (pid_t)syscall(SYS_gettid);
55 903 : (void)mmSetCurrentThreadName("AtraceMonitor");
56 2718 : while (g_stacktraceMonitorThreadStatus == THREAD_STATUS_RUN) {
57 935 : (void)usleep(STACKTRACE_SLEEP_PERIOD);
58 912 : if (g_stacktraceUpdateStatus == STACKTRACE_UPDATE_STATUS_START) {
59 : // ensure dl_iterate_phdr is not being called when fork
60 57 : (void)pthread_mutex_lock(&g_forkMutex);
61 57 : TraceStackUnwindInit();
62 57 : (void)pthread_mutex_unlock(&g_forkMutex);
63 :
64 57 : g_stacktraceUpdateStatus = STACKTRACE_UPDATE_STATUS_FINISH;
65 : }
66 : }
67 880 : return NULL;
68 : }
69 :
70 923 : static TraStatus StacktraceCreateMonitorThread(void)
71 : {
72 : mmUserBlock_t thread;
73 923 : thread.procFunc = StacktraceMonitorProcess;
74 923 : thread.pulArg = NULL;
75 923 : mmThreadAttr attr = { 0, 0, 0, 0, 0, 0, STACKTRACE_THREAD_STACK_SIZE };
76 923 : mmThread tid = 0;
77 923 : if (mmCreateTaskWithThreadAttr(&tid, &thread, &attr) != 0) {
78 20 : ADIAG_ERR("create task failed, strerr=%s.", strerror(errno));
79 20 : return TRACE_FAILURE;
80 : }
81 903 : g_stacktraceMonitorPthreadId = tid;
82 903 : return TRACE_SUCCESS;
83 : }
84 :
85 923 : static void StacktraceMonitorThreadInit(void)
86 : {
87 923 : g_stacktraceMonitorThreadStatus = THREAD_STATUS_RUN;
88 923 : g_stacktraceUpdateStatus = STACKTRACE_UPDATE_STATUS_INIT;
89 923 : TraStatus ret = StacktraceCreateMonitorThread();
90 923 : if (ret != TRACE_SUCCESS) {
91 : // call unwind in case thread creation fails
92 20 : g_stacktraceMonitorPthreadId = 0;
93 20 : ADIAG_ERR("Create monitor thread failed");
94 20 : return;
95 : }
96 : }
97 :
98 769 : static void StacktraceSubProcessInit(void)
99 : {
100 769 : if (!g_forking) {
101 : // sub process has been initialized
102 752 : return;
103 : }
104 17 : (void)pthread_mutex_unlock(&g_forkMutex);
105 17 : g_stacktraceMonitorThreadStatus = THREAD_STATUS_WAIT_EXIT;
106 17 : StacktraceMonitorThreadInit();
107 17 : g_forking = false;
108 : }
109 :
110 6985 : STATIC void StacktraceProcessUnInit(void)
111 : {
112 6985 : if (g_forking) {
113 6830 : return;
114 : }
115 155 : (void)pthread_mutex_lock(&g_forkMutex);
116 155 : g_forking = true; // set forking to true to avoid repeat uninit and init
117 : }
118 :
119 6216 : STATIC void StacktraceProcessInit(void)
120 : {
121 6216 : g_forking = false;
122 6216 : (void)pthread_mutex_unlock(&g_forkMutex);
123 6216 : }
124 :
125 906 : static void StacktracePrepareForFork(void)
126 : {
127 906 : int32_t ret = pthread_atfork((ThreadAtFork)StacktraceProcessUnInit, (ThreadAtFork)StacktraceProcessInit,
128 : (ThreadAtFork)StacktraceSubProcessInit);
129 906 : if (ret != 0) {
130 0 : ADIAG_WAR("can not call pthread_atfork, ret=%d", ret);
131 : }
132 906 : }
133 :
134 906 : void StacktraceMonitorInit(void)
135 : {
136 906 : StacktracePrepareForFork();
137 906 : StacktraceMonitorThreadInit();
138 906 : }
139 :
140 956 : void StacktraceMonitorExit(void)
141 : {
142 956 : if (g_stacktraceMonitorThreadStatus != THREAD_STATUS_RUN) {
143 92 : return;
144 : }
145 864 : g_stacktraceMonitorThreadStatus = THREAD_STATUS_WAIT_EXIT;
146 864 : if (g_stacktraceMonitorPthreadId != 0) {
147 844 : (void)mmJoinTask(&g_stacktraceMonitorPthreadId);
148 844 : g_stacktraceMonitorPthreadId = 0;
149 844 : g_stacktraceMonitorthreadId = 0;
150 : }
151 : }
|