From d41d3e86fcf9db1b308f0082898b7a17e4a9df4a Mon Sep 17 00:00:00 2001 From: sssooonnnggg Date: Mon, 25 May 2026 12:00:48 +0800 Subject: [PATCH] Defer Break action to the next line hook when no debugger has hit yet --- .../emmy_debugger/debugger/emmy_debugger_manager.h | 8 ++++++++ emmy_debugger/src/debugger/emmy_debugger.cpp | 11 +++++++++++ .../src/debugger/emmy_debugger_manager.cpp | 13 +++++++++++++ emmy_debugger/src/emmy_facade.cpp | 7 ------- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/emmy_debugger/include/emmy_debugger/debugger/emmy_debugger_manager.h b/emmy_debugger/include/emmy_debugger/debugger/emmy_debugger_manager.h index db2c6c7..7a60a39 100644 --- a/emmy_debugger/include/emmy_debugger/debugger/emmy_debugger_manager.h +++ b/emmy_debugger/include/emmy_debugger/debugger/emmy_debugger_manager.h @@ -47,6 +47,10 @@ class EmmyDebuggerManager void SetHitDebugger(std::shared_ptr debugger); + // 如果当前没有 hit debugger,pause(Break)请求会被挂起到这里, + // 由下一次任意 debugger 的 hook 触发时消费(原子读+清)。 + bool ConsumePendingBreak(); + bool IsDebuggerEmpty(); void AddBreakpoint(std::shared_ptr breakpoint); @@ -100,6 +104,10 @@ class EmmyDebuggerManager std::mutex breakDebuggerMtx; std::shared_ptr hitDebugger; + // pause(Break)请求挂起标记: DoAction(Break) 时若无 hitDebugger 就置位, + // hook 路径上首次进入 line 事件时消费。 + std::atomic pendingBreak{false}; + std::mutex breakpointsMtx; std::vector> breakpoints; diff --git a/emmy_debugger/src/debugger/emmy_debugger.cpp b/emmy_debugger/src/debugger/emmy_debugger.cpp index fe175c6..14caaa6 100644 --- a/emmy_debugger/src/debugger/emmy_debugger.cpp +++ b/emmy_debugger/src/debugger/emmy_debugger.cpp @@ -106,6 +106,17 @@ void Debugger::Hook(lua_Debug *ar, lua_State *L) { luaThreadExecutors.clear(); } } + + // 处理 pause: 如果 manager 上有挂起的 Break 请求(DoAction(Break) + // 时无 hitDebugger),这里消费一下,把当前 debugger 设为 hitDebugger, + // 然后走原来的 DoAction(Break) 路径设置 hookState = stateBreak。 + // 下面读 hookState 时就会拿到 stateBreak, ProcessHook 在当前 LINE + // 事件上立刻命中 HandleBreak。 + if (manager->ConsumePendingBreak()) { + manager->SetHitDebugger(shared_from_this()); + DoAction(DebugAction::Break); + } + auto bp = FindBreakPoint(ar); if (bp && ProcessBreakPoint(bp)) { HandleBreak(); diff --git a/emmy_debugger/src/debugger/emmy_debugger_manager.cpp b/emmy_debugger/src/debugger/emmy_debugger_manager.cpp index 56ef79d..a9eb9de 100644 --- a/emmy_debugger/src/debugger/emmy_debugger_manager.cpp +++ b/emmy_debugger/src/debugger/emmy_debugger_manager.cpp @@ -215,7 +215,20 @@ void EmmyDebuggerManager::DoAction(DebugAction action) if (debugger) { debugger->DoAction(action); + return; } + // 还没有 hit debugger: 只有 Break(pause) 在这种情况下有意义, + // 挂起 pending 标记,由下次任意 hook 触发时消费。 + // 其它 action(continue/step/stop) 必须在已断下后才有意义,这里直接丢弃。 + if (action == DebugAction::Break) + { + pendingBreak.store(true); + } +} + +bool EmmyDebuggerManager::ConsumePendingBreak() +{ + return pendingBreak.exchange(false); } void EmmyDebuggerManager::Eval(std::shared_ptr ctx) diff --git a/emmy_debugger/src/emmy_facade.cpp b/emmy_debugger/src/emmy_facade.cpp index 2465507..4f747ce 100644 --- a/emmy_debugger/src/emmy_facade.cpp +++ b/emmy_debugger/src/emmy_facade.cpp @@ -334,10 +334,6 @@ void EmmyFacade::Hook(lua_State *L, lua_Debug *ar) { return; } - // 没人断着时,把当前活跃 vm 记下来,使未断点过的 pause 能定位到目标 - if (!_emmyDebuggerManager.GetHitBreakpoint()) { - _emmyDebuggerManager.SetHitDebugger(debugger); - } debugger->Hook(ar, L); } else { if (workMode == WorkMode::Attach) { @@ -353,9 +349,6 @@ void EmmyFacade::Hook(lua_State *L, lua_Debug *ar) { this->transporter->Send(int(MessageCMD::AttachedNotify), obj); - if (!_emmyDebuggerManager.GetHitBreakpoint()) { - _emmyDebuggerManager.SetHitDebugger(debugger); - } debugger->Hook(ar, L); } }