diff options
author | Matthew Wild <mwild1@gmail.com> | 2018-03-18 12:05:38 +0000 |
---|---|---|
committer | Matthew Wild <mwild1@gmail.com> | 2018-03-18 12:05:38 +0000 |
commit | 8713a96ea622c3487420748db8ed15c8f880b65f (patch) | |
tree | f7fccbed41a1ebb6b4942767478b40c1917d0882 /util/async.lua | |
parent | 7d4e55d56724da8a4d393cee7d2a9d40f2cbb46a (diff) | |
download | prosody-8713a96ea622c3487420748db8ed15c8f880b65f.tar.gz prosody-8713a96ea622c3487420748db8ed15c8f880b65f.zip |
util.async: Split runner_continue into smaller functions for easier testing and safety
Diffstat (limited to 'util/async.lua')
-rw-r--r-- | util/async.lua | 37 |
1 files changed, 29 insertions, 8 deletions
diff --git a/util/async.lua b/util/async.lua index a07226de..4deb4295 100644 --- a/util/async.lua +++ b/util/async.lua @@ -9,6 +9,31 @@ local function checkthread() 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 function runner_continue(thread) 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 |