1e66f31c5Sopenharmony_ci/*
2e66f31c5Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
3e66f31c5Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4e66f31c5Sopenharmony_ci * you may not use this file except in compliance with the License.
5e66f31c5Sopenharmony_ci * You may obtain a copy of the License at
6e66f31c5Sopenharmony_ci *
7e66f31c5Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8e66f31c5Sopenharmony_ci *
9e66f31c5Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10e66f31c5Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11e66f31c5Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12e66f31c5Sopenharmony_ci * See the License for the specific language governing permissions and
13e66f31c5Sopenharmony_ci * limitations under the License.
14e66f31c5Sopenharmony_ci */
15e66f31c5Sopenharmony_ci#include "libuv_async_stack.h"
16e66f31c5Sopenharmony_ci
17e66f31c5Sopenharmony_ci#include <dlfcn.h>
18e66f31c5Sopenharmony_ci#include <pthread.h>
19e66f31c5Sopenharmony_ci#include <stdlib.h>
20e66f31c5Sopenharmony_ci#include <string.h>
21e66f31c5Sopenharmony_ci
22e66f31c5Sopenharmony_citypedef void(*LibuvSetStackIdFunc)(uint64_t stackId);
23e66f31c5Sopenharmony_citypedef uint64_t(*LibuvCollectAsyncStackFunc)();
24e66f31c5Sopenharmony_cistatic LibuvCollectAsyncStackFunc g_collectAsyncStackFunc = NULL;
25e66f31c5Sopenharmony_cistatic LibuvSetStackIdFunc g_setStackIdFunc = NULL;
26e66f31c5Sopenharmony_citypedef enum {
27e66f31c5Sopenharmony_ci    ASYNC_DFX_NOT_INIT,
28e66f31c5Sopenharmony_ci    ASYNC_DFX_DISABLE,
29e66f31c5Sopenharmony_ci    ASYNC_DFX_ENABLE
30e66f31c5Sopenharmony_ci} AsyncDfxInitStatus;
31e66f31c5Sopenharmony_ci
32e66f31c5Sopenharmony_cistatic AsyncDfxInitStatus g_enabledLibuvAsyncStackStatus = ASYNC_DFX_NOT_INIT;
33e66f31c5Sopenharmony_cistatic pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
34e66f31c5Sopenharmony_ci
35e66f31c5Sopenharmony_cistatic void LoadDfxAsyncStackLib()
36e66f31c5Sopenharmony_ci{
37e66f31c5Sopenharmony_ci    g_enabledLibuvAsyncStackStatus = ASYNC_DFX_DISABLE;
38e66f31c5Sopenharmony_ci    const char* debuggableEnv = getenv("HAP_DEBUGGABLE");
39e66f31c5Sopenharmony_ci    if ((debuggableEnv == NULL) || (strcmp(debuggableEnv, "true") != 0)) {
40e66f31c5Sopenharmony_ci        return;
41e66f31c5Sopenharmony_ci    }
42e66f31c5Sopenharmony_ci
43e66f31c5Sopenharmony_ci    // if async stack is not enabled, the lib should not be unloaded
44e66f31c5Sopenharmony_ci    void* asyncStackLibHandle = dlopen("libasync_stack.z.so", RTLD_NOW);
45e66f31c5Sopenharmony_ci    if (asyncStackLibHandle == NULL) {
46e66f31c5Sopenharmony_ci        return;
47e66f31c5Sopenharmony_ci    }
48e66f31c5Sopenharmony_ci
49e66f31c5Sopenharmony_ci    g_collectAsyncStackFunc = (LibuvCollectAsyncStackFunc)(dlsym(asyncStackLibHandle, "CollectAsyncStack"));
50e66f31c5Sopenharmony_ci    if (g_collectAsyncStackFunc == NULL) {
51e66f31c5Sopenharmony_ci        dlclose(asyncStackLibHandle);
52e66f31c5Sopenharmony_ci        asyncStackLibHandle = NULL;
53e66f31c5Sopenharmony_ci        return;
54e66f31c5Sopenharmony_ci    }
55e66f31c5Sopenharmony_ci
56e66f31c5Sopenharmony_ci    g_setStackIdFunc = (LibuvSetStackIdFunc)(dlsym(asyncStackLibHandle, "SetStackId"));
57e66f31c5Sopenharmony_ci    if (g_setStackIdFunc == NULL) {
58e66f31c5Sopenharmony_ci        g_collectAsyncStackFunc = NULL;
59e66f31c5Sopenharmony_ci        dlclose(asyncStackLibHandle);
60e66f31c5Sopenharmony_ci        asyncStackLibHandle = NULL;
61e66f31c5Sopenharmony_ci        return;
62e66f31c5Sopenharmony_ci    }
63e66f31c5Sopenharmony_ci
64e66f31c5Sopenharmony_ci    g_enabledLibuvAsyncStackStatus = ASYNC_DFX_ENABLE;
65e66f31c5Sopenharmony_ci}
66e66f31c5Sopenharmony_ci
67e66f31c5Sopenharmony_cistatic AsyncDfxInitStatus LibuvAsyncStackInit()
68e66f31c5Sopenharmony_ci{
69e66f31c5Sopenharmony_ci    if (g_enabledLibuvAsyncStackStatus == ASYNC_DFX_NOT_INIT) {
70e66f31c5Sopenharmony_ci        pthread_mutex_lock(&g_mutex);
71e66f31c5Sopenharmony_ci        if (g_enabledLibuvAsyncStackStatus == ASYNC_DFX_NOT_INIT) {
72e66f31c5Sopenharmony_ci            LoadDfxAsyncStackLib();
73e66f31c5Sopenharmony_ci        }
74e66f31c5Sopenharmony_ci        pthread_mutex_unlock(&g_mutex);
75e66f31c5Sopenharmony_ci    }
76e66f31c5Sopenharmony_ci    return g_enabledLibuvAsyncStackStatus;
77e66f31c5Sopenharmony_ci}
78e66f31c5Sopenharmony_ci
79e66f31c5Sopenharmony_ciuint64_t LibuvCollectAsyncStack(void)
80e66f31c5Sopenharmony_ci{
81e66f31c5Sopenharmony_ci    if (LibuvAsyncStackInit() == ASYNC_DFX_ENABLE) {
82e66f31c5Sopenharmony_ci        return g_collectAsyncStackFunc();
83e66f31c5Sopenharmony_ci    }
84e66f31c5Sopenharmony_ci
85e66f31c5Sopenharmony_ci    return 0;
86e66f31c5Sopenharmony_ci}
87e66f31c5Sopenharmony_ci
88e66f31c5Sopenharmony_civoid LibuvSetStackId(uint64_t stackId)
89e66f31c5Sopenharmony_ci{
90e66f31c5Sopenharmony_ci    if (LibuvAsyncStackInit() == ASYNC_DFX_ENABLE) {
91e66f31c5Sopenharmony_ci        return g_setStackIdFunc(stackId);
92e66f31c5Sopenharmony_ci    }
93e66f31c5Sopenharmony_ci}
94