Merge pull request #53 from idbrii/fix-async-lovejs

async: Skip wrapping with xpcall under lovejs
This commit is contained in:
Max Cahill 2022-03-07 10:50:36 +11:00 committed by GitHub
commit b6ca4c7740
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 8 deletions

View File

@ -73,6 +73,15 @@ function assert:type(a, t, msg, stack_level)
return a return a
end end
--assert a value is nil or a certain type.
-- useful for optional parameters.
function assert:type_or_nil(a, t, msg, stack_level)
if a ~= nil then
assert:type(a, t, msg, stack_level + 1)
end
return a
end
--replace everything in assert with nop functions that just return their second argument, for near-zero overhead on release --replace everything in assert with nop functions that just return their second argument, for near-zero overhead on release
function assert:nop() function assert:nop()
local nop = function(_, a) local nop = function(_, a)

View File

@ -16,6 +16,7 @@
]] ]]
local path = (...):gsub("async", "") local path = (...):gsub("async", "")
local assert = require(path .. "assert")
local class = require(path .. "class") local class = require(path .. "class")
local async = class({ local async = class({
@ -27,16 +28,33 @@ function async:new()
self.tasks_stalled = {} self.tasks_stalled = {}
end 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 --add a task to the kernel
function async:call(f, args, callback, error_callback) function async:call(f, args, callback, error_callback)
self:add(coroutine.create(function(...) assert:type_or_nil(args, "table", "async:call - args", 1)
local results = {xpcall(f, debug.traceback, ...)} f = capture_callstacks(f)
local success = table.remove(results, 1) self:add(coroutine.create(f), args, callback, error_callback)
if not success then
error(table.remove(results, 1))
end
return unpack(results)
end), args, callback, error_callback)
end end
--add an already-existing coroutine to the kernel --add an already-existing coroutine to the kernel