mirror of
https://github.com/1bardesign/batteries.git
synced 2024-11-10 02:31:48 +00:00
async: Skip wrapping with xpcall under lovejs
See Davidobot/love.js#54. lovejs crashes love with "attempt to yield across metamethod/C-call boundary" when you try to yield in a coroutine, so we skip wrapping. We lose the coroutine-local callstack, but at least it works. Here's my repro: local color = { purple = {0.25, 0.09, 0.28, 1}, white = {0.89, 0.91, 0.90, 1}, } local ball = { x = 100, y = 100, r = 20, } local S = {} local input = { vanilla = 'v', async = 'c', quit = 'escape', } function love.load() S.coro = async() end local function coro_fn() S.async_running = true for i=1,100 do color.purple[4] = i / 100 coroutine.yield() end color.purple[4] = 1 S.async_running = false return true end function love.update(dt) S.coro:update(dt) if S.vanilla then local success, result = coroutine.resume(S.vanilla) if result then print("coroutine cleared") S.vanilla = nil end end if not S.async_running then if love.keyboard.isDown(input.vanilla) then S.vanilla = coroutine.create(coro_fn) print("raw coroutine started") elseif love.keyboard.isDown(input.async) then print("Starting async call coroutine from update") S.coro:call(coro_fn) elseif love.keyboard.isDown(input.quit) then love.event.quit() end end end function love.draw() love.graphics.setColor(color.purple) love.graphics.circle("fill", ball.x, ball.y, ball.r) love.graphics.setColor(color.white) local str = "To start a coroutine:" for key,val in pairs(input) do str = ("%s\n%s: %s"):format(str, key, val) end love.graphics.printf(str, 5,5, 200, "left") end
This commit is contained in:
parent
f6a18380d4
commit
98f3630c07
32
async.lua
32
async.lua
@ -27,16 +27,32 @@ function async:new()
|
||||
self.tasks_stalled = {}
|
||||
end
|
||||
|
||||
local capture_callstacks
|
||||
if love.system.getOS() == 'Web' then
|
||||
-- Do no extra wrapping under lovejs because using xpcall causes "attempt
|
||||
-- to yield across metamethod/C-call boundary"
|
||||
capture_callstacks = function(f)
|
||||
return f
|
||||
end
|
||||
else
|
||||
capture_callstacks = function(f)
|
||||
-- Report errors with the coroutine's callstack instead of one coming
|
||||
-- from async:update.
|
||||
return function(...)
|
||||
local results = {xpcall(f, debug.traceback, ...)}
|
||||
local success = table.remove(results, 1)
|
||||
if not success then
|
||||
error(table.remove(results, 1))
|
||||
end
|
||||
return unpack(results)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--add a task to the kernel
|
||||
function async:call(f, args, callback, error_callback)
|
||||
self:add(coroutine.create(function(...)
|
||||
local results = {xpcall(f, debug.traceback, ...)}
|
||||
local success = table.remove(results, 1)
|
||||
if not success then
|
||||
error(table.remove(results, 1))
|
||||
end
|
||||
return unpack(results)
|
||||
end), args, callback, error_callback)
|
||||
f = capture_callstacks(f)
|
||||
self:add(coroutine.create(f), args, callback, error_callback)
|
||||
end
|
||||
|
||||
--add an already-existing coroutine to the kernel
|
||||
|
Loading…
Reference in New Issue
Block a user