support multiple simultaneous breakpoints in coroutines

This commit is contained in:
kepler155c@gmail.com
2020-05-28 22:04:20 -06:00
parent 8fef5d3580
commit 6394a48766
2 changed files with 59 additions and 37 deletions

View File

@@ -3,7 +3,13 @@
local fs = _G.fs local fs = _G.fs
local dbg = { } local dbg = {
hooks = { },
waits = { },
debugger = nil,
breakpoints = nil,
}
_G._dbg = dbg -- for testing purposes
local function breakpointHook(info) local function breakpointHook(info)
if dbg.breakpoints then if dbg.breakpoints then
@@ -22,15 +28,12 @@ local function functionHook(fn)
end end
local function stepHook() local function stepHook()
local co = coroutine.running() return function()
return function(info) return true
return co == coroutine.running()
or breakpointHook(info)
end end
end end
local function stackSizeHook(n) local function stackSizeHook(n)
local co = coroutine.running()
local i = 2 local i = 2
while true do while true do
local info = debug.getinfo(i) local info = debug.getinfo(i)
@@ -40,8 +43,7 @@ local function stackSizeHook(n)
i = i + 1 i = i + 1
end end
return function(info) return function(info)
return co == coroutine.running() return not debug.getinfo(i - n)
and not debug.getinfo(i - n)
or breakpointHook(info) or breakpointHook(info)
end end
end end
@@ -54,8 +56,6 @@ local function stepOverHook()
return stackSizeHook(0) return stackSizeHook(0)
end end
local hookEval = function() end
-- Create a table of all the locally accessible variables. -- Create a table of all the locally accessible variables.
local function local_bindings(offset, stack_inspect_offset) local function local_bindings(offset, stack_inspect_offset)
offset = offset + 1 + stack_inspect_offset -- add this function to the offset offset = offset + 1 + stack_inspect_offset -- add this function to the offset
@@ -133,14 +133,12 @@ local function get_trace(offset, stack_inspect_offset)
return t return t
end end
local inHook = false
local function hook() local function hook()
local info = debug.getinfo(2) local info = debug.getinfo(2)
if not inHook and hookEval(info) then local h = dbg.hooks[coroutine.running()]
inHook = true
if h and h.eval(info) then
local inspectOffset = 0 local inspectOffset = 0
repeat repeat
@@ -153,6 +151,10 @@ local function hook()
} }
inspectOffset = 0 -- reset inspectOffset = 0 -- reset
table.insert(dbg.waits, h)
while dbg.waits[1] ~= h do
os.sleep(.1)
end
os.queueEvent('debuggerX', dbg.debugger.uid, snapshot) os.queueEvent('debuggerX', dbg.debugger.uid, snapshot)
local e, cmd, param local e, cmd, param
@@ -160,25 +162,24 @@ local function hook()
e, cmd, param = os.pullEvent('debugger') e, cmd, param = os.pullEvent('debugger')
until e == 'debugger' until e == 'debugger'
table.remove(dbg.waits, 1)
if cmd == 's' then if cmd == 's' then
hookEval = stepHook() h.eval = stepHook()
elseif cmd == 'n' then elseif cmd == 'n' then
hookEval = stepOverHook() h.eval = stepOverHook()
elseif cmd == 'f' then elseif cmd == 'f' then
hookEval = stepOutHook() h.eval = stepOutHook()
elseif cmd == 'c' then elseif cmd == 'c' then
hookEval = breakpointHook h.eval = breakpointHook
elseif cmd == 'i' then elseif cmd == 'i' then
-- get snapshot of stack at this offset -- get snapshot of stack at this offset
inspectOffset = param inspectOffset = param
done = false done = false
else else
os.sleep(1)
done = false done = false
end end
until done until done
inHook = false
end end
end end
@@ -189,19 +190,23 @@ function dbg.call(fn, ...)
fn(table.unpack(args)) fn(table.unpack(args))
end, end,
function(err) function(err)
hookEval = stepHook() dbg.hooks[coroutine.running()].eval = stepHook()
-- An error has occurred -- An error has occurred
return err return err
end) end)
end end
_ENV.coroutine = setmetatable({ dbg.stopIn = function(fn)
dbg.hooks[coroutine.running()].eval = functionHook(fn)
end
_ENV.coroutine = setmetatable({
create = function(fn) create = function(fn)
local co = _G.coroutine.create(function(...) local co = _G.coroutine.create(function(...)
local r = { dbg.call(fn, ...) } local r = { dbg.call(fn, ...) }
dbg.hooks[coroutine.running()] = nil
if not r[1] then if not r[1] then
error(r[2], -1) error(r[2], -1)
end end
@@ -209,24 +214,19 @@ _ENV.coroutine = setmetatable({
return table.unpack(r, 2) return table.unpack(r, 2)
end) end)
dbg.hooks[co] = {
co = co,
eval = breakpointHook,
}
debug.sethook(co, hook, 'l') debug.sethook(co, hook, 'l')
return co return co
end end
--[[
create = function(f)
local co = _G.coroutine.create(f)
debug.sethook(co, hook, 'l')
return co
end
]]
}, { __index = coroutine }) }, { __index = coroutine })
dbg.hooks[coroutine.running()] = {
co = coroutine.running(),
eval = function() return false end,
}
debug.sethook(hook, 'l') debug.sethook(hook, 'l')
-- Expose the debugger's functions
dbg.stopIn = function(fn)
hookEval = functionHook(fn)
end
dbg.debugger = nil
return dbg return dbg

View File

@@ -10,6 +10,28 @@ local function method(times)
return m2(a) return m2(a)
end end
local Event = require('opus.event')
Event.on('event1', function()
print('event1')
end)
Event.on('event2', function()
print('event2')
end)
Event.onTimeout(10, function()
Event.exitPullEvents()
end)
local function xx()
os.queueEvent('event1')
os.queueEvent('event2')
Event.pullEvents()
end
xx()
local chunk = load([[ local chunk = load([[
local j = 5 local j = 5
for i = 1, 5 do for i = 1, 5 do