myspace / CommonLua /Core /asyncop.lua
sirnii's picture
Upload 1816 files
b6a38d7 verified
raw
history blame
5.29 kB
--- Initializes the AsyncOps table if it doesn't already exist.
-- This is executed when the file is first loaded.
-- @local
if FirstLoad then
AsyncOps = {}
end
--- Wakes up the async operation with the given ID and removes it from the AsyncOps table.
-- @param opid number The ID of the async operation to complete.
-- @param ... any The return values to pass to the async operation's callback.
function AsyncOpDone(opid, ...)
Wakeup(AsyncOps[opid], ...)
AsyncOps[opid] = nil
end
--- Wakes up an async operation with the given ID and removes it from the AsyncOps table.
-- If the operation has timed out, it removes the operation from AsyncOps and returns "timeout".
-- If the operation has been cancelled, it removes the operation from AsyncOps and returns "cancelled".
-- Otherwise, it returns the return values of the async operation's callback.
-- @param id number The ID of the async operation to complete.
-- @param ok boolean Whether the operation completed successfully.
-- @param ... any The return values to pass to the async operation's callback.
-- @return string|any Either "timeout", "cancelled", or the return values of the async operation's callback.
local function __wakeup(id, ok, ...)
if not ok then
AsyncOps[id] = nil
AsyncOpStop(id)
return "timeout"
end
if AsyncOps[id] then
assert(AsyncOps[id] == "cancelled", "Async op thread has been awaken before the computation is finished!")
AsyncOps[id] = nil
return "cancelled"
end
return ...
end
--- Checks if the current thread can yield.
-- This is a wrapper around the built-in `CanYield` function.
-- @return boolean True if the current thread can yield, false otherwise.
AsyncCanYield = CanYield
--- Wraps an asynchronous function to provide timeout and cancellation support.
-- The wrapped function will wait until the asynchronous operation is complete, fails, times out, or is cancelled.
-- @param func function The asynchronous function to wrap.
-- @return function The wrapped asynchronous function.
local function AsyncOpWrap(func)
return function(...)
-- async operations can be executed outside of threads or in real time threads only (cannot be persisted)
if not IsRealTimeThread() or not AsyncCanYield() then
-- exec syncronously
return func(nil, ...)
end
local id, res2, res3, res4 = func(true, ...)
if type(id) ~= "number" then
return id, res2, res3, res4
end
AsyncOps[id] = CurrentThread()
return __wakeup(id, WaitWakeup())
end
end
--- Wraps all asynchronous functions in the `async` table with a function that provides timeout and cancellation support.
-- The wrapped functions will wait until the asynchronous operation is complete, fails, times out, or is cancelled.
-- This allows for consistent handling of asynchronous operations throughout the codebase.
for op, func in pairs(async) do
_G[op] = AsyncOpWrap(func)
end
--- AsyncOp call with timeout and cancel support, the function waits until the async op is complete, fails, timeouts or is cancelled.
-- @cstyle err, ... AsyncOpWait(int nTimeout, table id_ref, string funcname, ...).
-- @param nTimeout int; timeout in milliseconds, can be nil.
-- @param id_ref table; table to store the id of the async operation; can be used to call AsyncOpCancel(id_ref), overwrites member "asyncop_id" - the same table should not be used for concurent AsyncOp calls; can be nil.
-- @param funcname string; name of the async function to be called, actual function is found in async[funcname].
-- @param ...; arguments passed to the async function.
-- @return err, ...; if there is no err, the async op was successful and the rest of the return values are returned by the async op;
function AsyncOpWait(timeout, id_ref, funcname, ...)
-- async operations can be executed in real time threads only (cannot be persisted)
assert(IsRealTimeThread())
local id, res2, res3, res4 = async[funcname](true, ...)
if type(id) ~= "number" then
return id, res2, res3, res4
end
if id_ref then
rawset(id_ref, "asyncop_id", id)
end
AsyncOps[id] = CurrentThread()
return __wakeup(id, WaitWakeup(timeout))
end
--- Cancels an AsyncOp started with AsyncOpWait.
-- @cstyle bool AsyncOpCancel(table id_ref).
-- @param id_ref table; a thread or a table passed to AsyncOpWait used to identify the async op call; the same table should not be used for concurent AsyncOp calls.
-- @return bool; true if the operation referenced in id_ref was waiting to complete.
function AsyncOpCancel(id_ref)
local id, thread
if type(id_ref) == "thread" then
for _id, _thread in pairs(AsyncOps) do
if _thread == id_ref then
id = _id
thread = _thread
end
end
elseif type(id_ref) == "table" then
id = rawget(id_ref, "asyncop_id")
rawset(id_ref, "asyncop_id", nil)
thread = id and AsyncOps[id]
end
if thread then
AsyncOps[id] = "cancelled"
AsyncOpStop(id)
return Wakeup(thread)
end
end
-- AsyncOpWait/AsyncOpCancel usage:
-- ...
-- local err, res1, res2, res3 = AsyncOpWait(5000, self, "WebRequest", ...)
-- if not err then ... end
-- if err == "cancelled" then ... end
-- if err == "timeout" then ... end
--
-- in another thread/callback:
-- AsyncOpCancel(self)