Reputation: 61
A simple example:
coroutine.resume(coroutine.create(function()
print(debug.traceback())
end))
print(debug.traceback())
the output:
stack traceback:
./v.lua:2: in function <./v.lua:1>
stack traceback:
./v.lua:4: in main chunk
[C]: in ?
It shows that traceback
inside a coroutine doesn't know about how it is resumed, so that xxx: in main chunk
doesn't show.
How can I get the complete stacktrace inside a coroutine?
Upvotes: 4
Views: 750
Reputation: 61
Well, I found a workaround here.
Since one Lua VM has only one execution point at one time (and that's why a full call stack is there), we can record resumption information manually.
In lua, manually build a resume-stack trace.
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
Other tips:
Using global table to store threads also works. But you still need to capture main thread so that it can be traced everywhere.
Writing codes in C function can prevent traceback into hooked coroutine.resume
and debug.traceback
itself, give you a clearer output.
You won't get much performance hit when debug.traceback
is not called.
Upvotes: 2