Software /
code /
prosody
Diff
util/async.lua @ 8627:24b59a62acce
util.async: Split runner_continue into smaller functions for easier testing and safety
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Sun, 18 Mar 2018 12:05:38 +0000 |
parent | 8625:08bf4df6fdb7 |
child | 8629:ddb04cacb8b1 |
line wrap: on
line diff
--- a/util/async.lua Sun Mar 18 11:32:00 2018 +0000 +++ b/util/async.lua Sun Mar 18 12:05:38 2018 +0000 @@ -9,6 +9,31 @@ return thread; end +local function runner_from_thread(thread) + local level = 0; + -- Find the 'level' of the top-most function (0 == current level, 1 == caller, ...) + while debug.getinfo(thread, level, "") do level = level + 1; end + local name, runner = debug.getlocal(thread, level-1, 1); + if name ~= "self" or type(runner) ~= "table" or runner.thread ~= thread then + return nil; + end + return runner; +end + +local function call_watcher(runner, watcher_name, ...) + local watcher = runner.watchers[watcher_name]; + if not watcher then + return false; + end + runner:log("debug", "Calling '%s' watcher", watcher_name); + local ok, err = pcall(watcher, runner, ...); -- COMPAT: Switch to xpcall after Lua 5.1 + if not ok then + runner:log("error", "Error in '%s' watcher: %s", watcher_name, err); + return nil, err; + end + return true; +end + local function runner_continue(thread) -- ASSUMPTION: runner is in 'waiting' state (but we don't have the runner to know for sure) if coroutine.status(thread) ~= "suspended" then -- This should suffice @@ -20,16 +45,12 @@ local err = state; -- Running the coroutine failed, which means we have to find the runner manually, -- in order to inform the error handler - local level = 0; - -- Find the 'level' of the top-most function (0 == current level, 1 == caller, ...) - while debug.getinfo(thread, level, "") do level = level + 1; end - ok, runner = debug.getlocal(thread, level-1, 1); - if ok ~= "self" or runner.thread ~= thread then - log("warn", "unexpected async state: unable to locate runner during error handling, got %s", ok); + runner = runner_from_thread(thread); + if not runner then + log("warn", "unexpected async state: unable to locate runner during error handling"); return false; end - local error_handler = runner.watchers.error; - if error_handler then error_handler(runner, debug.traceback(thread, err)); end + call_watcher(runner, "error", debug.traceback(thread, err)); runner.state, runner.thread = "ready", nil; return runner:run(); elseif state == "ready" then