问题描述
一个简单的例子:
coroutine.resume(coroutine.create(function()
print(debug.traceback())
end))
print(debug.traceback())
输出:
stack traceback:
./v.lua:2: in function <./v.lua:1>
stack traceback:
./v.lua:4: in main chunk
[C]: in ?
它表明协程中的 traceback
不知道它是如何恢复的,因此 xxx: in main chunk
不显示。
如何在协程中获取完整的堆栈跟踪?
解决方法
好吧,我在这里找到了解决方法。
由于一个 Lua VM 一次只有一个执行点(这就是为什么那里有一个完整的调用堆栈),我们可以手动记录恢复信息。
在 lua 中,手动构建恢复堆栈跟踪。
local xresume = coroutine.resume
local xtrace = debug.traceback
-- magic here! Take care of main thread.
local mainthr = coroutine.running() -- captureing is a must.
debug.traceback = function(athr)
if athr then return xtrace(athr) end -- no interest in specified thread.
return xtrace(mainthr)
end
coroutine.resume = function(thr,...)
-- another magic.
local uptrace = debug.traceback
debug.traceback = function(athr)
if athr then return xtrace(athr) end -- no interest in specified thread.
return xtrace(thr) -- trace the stack of thr.
.. '\n' .. uptrace() -- trace from thr's resume point.
end
local result = { xresume(thr,...) }
debug.traceback = uptrace
return table.unpack(result)
end
其他提示:
-
使用全局表来存储线程也有效。但是你还是需要捕获主线程,这样才能到处追踪。
-
在 C 函数中编写代码可以防止回溯到钩子
coroutine.resume
和debug.traceback
本身,为您提供更清晰的输出。 -
如果不调用
debug.traceback
,您的性能不会受到太大影响。