mirror of
https://gitee.com/openharmony/arkcompiler_toolchain
synced 2024-11-23 23:49:50 +00:00
modify inspector
description:modify inspector issue:https://gitee.com/openharmony-sig/arkcompiler_toolchain/issues/I5HX4T Signed-off-by: buzhuyu <buzhuyu@huawei.com>
This commit is contained in:
parent
241005bcb7
commit
0dc8ac44b1
@ -14,3 +14,256 @@
|
||||
*/
|
||||
|
||||
#include "inspector/inspector.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <shared_mutex>
|
||||
#include <unistd.h>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "base/log/log.h"
|
||||
#include "inspector/ws_server.h"
|
||||
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
namespace {
|
||||
enum DispatchStatus : int32_t {
|
||||
UNKNOWN = 0,
|
||||
DISPATCHING,
|
||||
DISPATCHED
|
||||
};
|
||||
|
||||
using InitializeDebugger = void(*)(void*, const std::function<void(const void*, const std::string&)>&);
|
||||
using UninitializeDebugger = void(*)(void*);
|
||||
using WaitForDebugger = void(*)(void*);
|
||||
using DispatchMessage = void(*)(void*, std::string&&);
|
||||
using ProcessMessage = void(*)(void*);
|
||||
using GetDispatchStatus = int32_t(*)(void*);
|
||||
|
||||
DispatchMessage g_dispatchMessage = nullptr;
|
||||
InitializeDebugger g_initializeDebugger = nullptr;
|
||||
UninitializeDebugger g_uninitializeDebugger = nullptr;
|
||||
WaitForDebugger g_waitForDebugger = nullptr;
|
||||
ProcessMessage g_processMessage = nullptr;
|
||||
GetDispatchStatus g_getDispatchStatus = nullptr;
|
||||
|
||||
std::atomic<bool> g_hasArkFuncsInited = false;
|
||||
std::unordered_map<const void*, Inspector*> g_inspectors;
|
||||
std::shared_mutex g_mutex;
|
||||
|
||||
thread_local void* g_handle = nullptr;
|
||||
thread_local void* g_vm = nullptr;
|
||||
|
||||
constexpr char ARK_DEBUGGER_SHARED_LIB[] = "libark_ecma_debugger.so";
|
||||
|
||||
void* HandleClient(void* const server)
|
||||
{
|
||||
LOGI("HandleClient");
|
||||
if (server == nullptr) {
|
||||
LOGE("HandleClient server nullptr");
|
||||
return nullptr;
|
||||
}
|
||||
static_cast<WsServer*>(server)->RunServer();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool LoadArkDebuggerLibrary()
|
||||
{
|
||||
if (g_handle != nullptr) {
|
||||
LOGE("Already opened");
|
||||
return false;
|
||||
}
|
||||
g_handle = dlopen(ARK_DEBUGGER_SHARED_LIB, RTLD_LAZY);
|
||||
if (g_handle == nullptr) {
|
||||
LOGE("Failed to open %{public}s, reason: %{public}sn", ARK_DEBUGGER_SHARED_LIB, dlerror());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void* GetArkDynFunction(const char* symbol)
|
||||
{
|
||||
auto function = dlsym(g_handle, symbol);
|
||||
if (function == nullptr) {
|
||||
LOGE("Failed to get symbol %{public}s in %{public}s", symbol, ARK_DEBUGGER_SHARED_LIB);
|
||||
}
|
||||
return function;
|
||||
}
|
||||
|
||||
void SendReply(const void* vm, const std::string& message)
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock(g_mutex);
|
||||
auto iter = g_inspectors.find(vm);
|
||||
if (iter != g_inspectors.end() && iter->second != nullptr &&
|
||||
iter->second->websocketServer_ != nullptr) {
|
||||
iter->second->websocketServer_->SendReply(message);
|
||||
}
|
||||
}
|
||||
|
||||
void ResetServiceLocked()
|
||||
{
|
||||
auto iter = g_inspectors.find(g_vm);
|
||||
if (iter != g_inspectors.end() && iter->second != nullptr &&
|
||||
iter->second->websocketServer_ != nullptr) {
|
||||
iter->second->websocketServer_->StopServer();
|
||||
delete iter->second;
|
||||
iter->second = nullptr;
|
||||
g_inspectors.erase(iter);
|
||||
}
|
||||
if (g_handle != nullptr) {
|
||||
dlclose(g_handle);
|
||||
g_handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool InitializeInspector(void* vm, const std::string& componentName, int32_t instanceId,
|
||||
const DebuggerPostTask& debuggerPostTask)
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock(g_mutex);
|
||||
auto iter = g_inspectors.find(vm);
|
||||
if (iter != g_inspectors.end()) {
|
||||
LOGE("Already have the same vm in the map");
|
||||
return false;
|
||||
}
|
||||
|
||||
Inspector *newInspector = new Inspector();
|
||||
if (!g_inspectors.emplace(vm, newInspector).second) {
|
||||
delete newInspector;
|
||||
return false;
|
||||
}
|
||||
|
||||
newInspector->tid_ = pthread_self();
|
||||
newInspector->vm_ = vm;
|
||||
newInspector->debuggerPostTask_ = debuggerPostTask;
|
||||
newInspector->websocketServer_ = std::make_unique<WsServer>(componentName,
|
||||
std::bind(&Inspector::OnMessage, newInspector, std::placeholders::_1), instanceId);
|
||||
|
||||
pthread_t tid;
|
||||
if (pthread_create(&tid, nullptr, &HandleClient, static_cast<void *>(
|
||||
newInspector->websocketServer_.get())) != 0) {
|
||||
LOGE("Create inspector thread failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InitializeArkFunctions()
|
||||
{
|
||||
// no need to initialize again in case of multi-instance
|
||||
if (g_hasArkFuncsInited) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_lock<std::shared_mutex> lock(g_mutex);
|
||||
if (g_hasArkFuncsInited) {
|
||||
return true;
|
||||
}
|
||||
g_initializeDebugger = reinterpret_cast<InitializeDebugger>(
|
||||
GetArkDynFunction("InitializeDebugger"));
|
||||
if (g_initializeDebugger == nullptr) {
|
||||
ResetServiceLocked();
|
||||
return false;
|
||||
}
|
||||
g_uninitializeDebugger = reinterpret_cast<UninitializeDebugger>(
|
||||
GetArkDynFunction("UninitializeDebugger"));
|
||||
if (g_uninitializeDebugger == nullptr) {
|
||||
ResetServiceLocked();
|
||||
return false;
|
||||
}
|
||||
g_waitForDebugger = reinterpret_cast<WaitForDebugger>(
|
||||
GetArkDynFunction("WaitForDebugger"));
|
||||
if (g_waitForDebugger == nullptr) {
|
||||
ResetServiceLocked();
|
||||
return false;
|
||||
}
|
||||
g_dispatchMessage = reinterpret_cast<DispatchMessage>(
|
||||
GetArkDynFunction("DispatchMessage"));
|
||||
if (g_dispatchMessage == nullptr) {
|
||||
ResetServiceLocked();
|
||||
return false;
|
||||
}
|
||||
g_getDispatchStatus = reinterpret_cast<GetDispatchStatus>(
|
||||
GetArkDynFunction("GetDispatchStatus"));
|
||||
if (g_getDispatchStatus == nullptr) {
|
||||
ResetServiceLocked();
|
||||
return false;
|
||||
}
|
||||
g_processMessage = reinterpret_cast<ProcessMessage>(
|
||||
GetArkDynFunction("ProcessMessage"));
|
||||
if (g_processMessage == nullptr) {
|
||||
ResetServiceLocked();
|
||||
return false;
|
||||
}
|
||||
|
||||
g_hasArkFuncsInited = true;
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void Inspector::OnMessage(std::string&& msg)
|
||||
{
|
||||
g_dispatchMessage(vm_, std::move(msg));
|
||||
|
||||
// message will be processed soon if the debugger thread is in running or waiting status
|
||||
if (g_getDispatchStatus(vm_) != DispatchStatus::UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
usleep(DELAY_CHECK_DISPATCH_STATUS);
|
||||
if (g_getDispatchStatus(vm_) != DispatchStatus::UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
// the debugger thread maybe in idle status, so try to post a task to wake it up
|
||||
if (debuggerPostTask_ != nullptr) {
|
||||
debuggerPostTask_([tid = tid_, vm = vm_] {
|
||||
if (tid != pthread_self()) {
|
||||
LOGE("Task not in debugger thread");
|
||||
return;
|
||||
}
|
||||
g_processMessage(vm);
|
||||
});
|
||||
} else {
|
||||
LOGW("No debuggerPostTask provided");
|
||||
}
|
||||
}
|
||||
|
||||
bool StartDebug(const std::string& componentName, void* vm, bool isDebugMode, int32_t instanceId,
|
||||
const DebuggerPostTask& debuggerPostTask)
|
||||
{
|
||||
LOGI("StartDebug: %{private}s", componentName.c_str());
|
||||
g_vm = vm;
|
||||
if (!LoadArkDebuggerLibrary()) {
|
||||
return false;
|
||||
}
|
||||
if (!InitializeArkFunctions()) {
|
||||
LOGE("Initialize ark functions failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_initializeDebugger(vm, std::bind(&SendReply, vm, std::placeholders::_2));
|
||||
|
||||
if (!InitializeInspector(vm, componentName, instanceId, debuggerPostTask)) {
|
||||
LOGE("Initialize inspector failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isDebugMode) {
|
||||
g_waitForDebugger(vm);
|
||||
}
|
||||
LOGI("StartDebug Continue");
|
||||
return true;
|
||||
}
|
||||
|
||||
void StopDebug(const std::string& componentName)
|
||||
{
|
||||
LOGI("StopDebug: %{private}s", componentName.c_str());
|
||||
std::unique_lock<std::shared_mutex> lock(g_mutex);
|
||||
auto iter = g_inspectors.find(g_vm);
|
||||
if (iter == g_inspectors.end() || iter->second == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_uninitializeDebugger(g_vm);
|
||||
ResetServiceLocked();
|
||||
LOGI("StopDebug end");
|
||||
}
|
||||
} // namespace OHOS::ArkCompiler::Toolchain
|
||||
|
@ -16,4 +16,49 @@
|
||||
#ifndef ARKCOMPILER_TOOLCHAIN_INSPECTOR_INSPECTOR_H
|
||||
#define ARKCOMPILER_TOOLCHAIN_INSPECTOR_INSPECTOR_H
|
||||
|
||||
#include "ws_server.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace panda::ecmascript {
|
||||
class EcmaVM;
|
||||
} // namespace panda::ecmascript
|
||||
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
using EcmaVM = panda::ecmascript::EcmaVM;
|
||||
using DebuggerPostTask = std::function<void(std::function<void()>&&)>;
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
bool StartDebug(const std::string& componentName, void* vm, bool isDebugMode, int32_t instanceId,
|
||||
const DebuggerPostTask& debuggerPostTask);
|
||||
|
||||
void StopDebug(const std::string& componentName);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class Inspector {
|
||||
public:
|
||||
Inspector() = default;
|
||||
~Inspector() = default;
|
||||
|
||||
void OnMessage(std::string&& msg);
|
||||
|
||||
static constexpr int32_t DELAY_CHECK_DISPATCH_STATUS = 100;
|
||||
|
||||
pthread_t tid_ = 0;
|
||||
void* vm_ = nullptr;
|
||||
std::unique_ptr<WsServer> websocketServer_;
|
||||
DebuggerPostTask debuggerPostTask_;
|
||||
};
|
||||
} // namespace OHOS::ArkCompiler::Toolchain
|
||||
|
||||
#endif // ARKCOMPILER_TOOLCHAIN_INSPECTOR_INSPECTOR_H
|
Loading…
Reference in New Issue
Block a user