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:
buzhuyu 2022-07-20 11:43:03 +08:00
parent 241005bcb7
commit 0dc8ac44b1
2 changed files with 298 additions and 0 deletions

View File

@ -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

View File

@ -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