LCOV - code coverage report
Current view: top level - atrace/utrace/stacktrace - stacktrace_monitor.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 92.8 % 69 64
Test Date: 2026-07-28 10:53:44 Functions: 83.3 % 12 10

            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              : }
        

Generated by: LCOV version 2.0-1