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 88 : void StacktraceMonitorStartUpdate(void) { g_stacktraceUpdateStatus = STACKTRACE_UPDATE_STATUS_START; }
36 :
37 0 : pid_t StacktraceMonitorGetTid(void) { return g_stacktraceMonitorthreadId; }
38 :
39 0 : bool StacktraceCheckUpdateFinished(void) { return (g_stacktraceUpdateStatus == STACKTRACE_UPDATE_STATUS_FINISH); }
40 :
41 1010 : static void* StacktraceMonitorProcess(void* arg)
42 : {
43 : (void)arg;
44 1010 : g_stacktraceMonitorthreadId = (pid_t)syscall(SYS_gettid);
45 1010 : (void)mmSetCurrentThreadName("AtraceMonitor");
46 3029 : while (g_stacktraceMonitorThreadStatus == THREAD_STATUS_RUN) {
47 1034 : (void)usleep(STACKTRACE_SLEEP_PERIOD);
48 1009 : if (g_stacktraceUpdateStatus == STACKTRACE_UPDATE_STATUS_START) {
49 : // ensure dl_iterate_phdr is not being called when fork
50 63 : (void)pthread_mutex_lock(&g_forkMutex);
51 63 : TraceStackUnwindInit();
52 63 : (void)pthread_mutex_unlock(&g_forkMutex);
53 :
54 63 : g_stacktraceUpdateStatus = STACKTRACE_UPDATE_STATUS_FINISH;
55 : }
56 : }
57 985 : return NULL;
58 : }
59 :
60 1032 : static TraStatus StacktraceCreateMonitorThread(void)
61 : {
62 : mmUserBlock_t thread;
63 1032 : thread.procFunc = StacktraceMonitorProcess;
64 1032 : thread.pulArg = NULL;
65 1032 : mmThreadAttr attr = {0, 0, 0, 0, 0, 0, STACKTRACE_THREAD_STACK_SIZE};
66 1032 : mmThread tid = 0;
67 1032 : if (mmCreateTaskWithThreadAttr(&tid, &thread, &attr) != 0) {
68 22 : ADIAG_ERR("create task failed, strerr=%s.", strerror(errno));
69 22 : return TRACE_FAILURE;
70 : }
71 1010 : g_stacktraceMonitorPthreadId = tid;
72 1010 : return TRACE_SUCCESS;
73 : }
74 :
75 1032 : static void StacktraceMonitorThreadInit(void)
76 : {
77 1032 : g_stacktraceMonitorThreadStatus = THREAD_STATUS_RUN;
78 1032 : g_stacktraceUpdateStatus = STACKTRACE_UPDATE_STATUS_INIT;
79 1032 : TraStatus ret = StacktraceCreateMonitorThread();
80 1032 : if (ret != TRACE_SUCCESS) {
81 : // call unwind in case thread creation fails
82 22 : g_stacktraceMonitorPthreadId = 0;
83 22 : ADIAG_ERR("Create monitor thread failed");
84 22 : return;
85 : }
86 : }
87 :
88 882 : static void StacktraceSubProcessInit(void)
89 : {
90 882 : if (!g_forking) {
91 : // sub process has been initialized
92 863 : return;
93 : }
94 19 : (void)pthread_mutex_unlock(&g_forkMutex);
95 19 : g_stacktraceMonitorThreadStatus = THREAD_STATUS_WAIT_EXIT;
96 19 : StacktraceMonitorThreadInit();
97 19 : g_forking = false;
98 : }
99 :
100 9702 : STATIC void StacktraceProcessUnInit(void)
101 : {
102 9702 : if (g_forking) {
103 9493 : return;
104 : }
105 209 : (void)pthread_mutex_lock(&g_forkMutex);
106 209 : g_forking = true; // set forking to true to avoid repeat uninit and init
107 : }
108 :
109 8820 : STATIC void StacktraceProcessInit(void)
110 : {
111 8820 : g_forking = false;
112 8820 : (void)pthread_mutex_unlock(&g_forkMutex);
113 8820 : }
114 :
115 1013 : static void StacktracePrepareForFork(void)
116 : {
117 1013 : int32_t ret = pthread_atfork(
118 : (ThreadAtFork)StacktraceProcessUnInit, (ThreadAtFork)StacktraceProcessInit,
119 : (ThreadAtFork)StacktraceSubProcessInit);
120 1013 : if (ret != 0) {
121 0 : ADIAG_WAR("can not call pthread_atfork, ret=%d", ret);
122 : }
123 1013 : }
124 :
125 1013 : void StacktraceMonitorInit(void)
126 : {
127 1013 : StacktracePrepareForFork();
128 1013 : StacktraceMonitorThreadInit();
129 1013 : }
130 :
131 1069 : void StacktraceMonitorExit(void)
132 : {
133 1069 : if (g_stacktraceMonitorThreadStatus != THREAD_STATUS_RUN) {
134 102 : return;
135 : }
136 967 : g_stacktraceMonitorThreadStatus = THREAD_STATUS_WAIT_EXIT;
137 967 : if (g_stacktraceMonitorPthreadId != 0) {
138 945 : (void)mmJoinTask(&g_stacktraceMonitorPthreadId);
139 945 : g_stacktraceMonitorPthreadId = 0;
140 945 : g_stacktraceMonitorthreadId = 0;
141 : }
142 : }
|