Mercurial > prosody-hg
comparison 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 |
| parents | 08bf4df6fdb7 |
| children | ddb04cacb8b1 |
comparison
equal
deleted
inserted
replaced
| 8626:20532f191f8d | 8627:24b59a62acce |
|---|---|
| 5 local thread, main = coroutine.running(); | 5 local thread, main = coroutine.running(); |
| 6 if not thread or main then | 6 if not thread or main then |
| 7 error("Not running in an async context, see https://prosody.im/doc/developers/util/async"); | 7 error("Not running in an async context, see https://prosody.im/doc/developers/util/async"); |
| 8 end | 8 end |
| 9 return thread; | 9 return thread; |
| 10 end | |
| 11 | |
| 12 local function runner_from_thread(thread) | |
| 13 local level = 0; | |
| 14 -- Find the 'level' of the top-most function (0 == current level, 1 == caller, ...) | |
| 15 while debug.getinfo(thread, level, "") do level = level + 1; end | |
| 16 local name, runner = debug.getlocal(thread, level-1, 1); | |
| 17 if name ~= "self" or type(runner) ~= "table" or runner.thread ~= thread then | |
| 18 return nil; | |
| 19 end | |
| 20 return runner; | |
| 21 end | |
| 22 | |
| 23 local function call_watcher(runner, watcher_name, ...) | |
| 24 local watcher = runner.watchers[watcher_name]; | |
| 25 if not watcher then | |
| 26 return false; | |
| 27 end | |
| 28 runner:log("debug", "Calling '%s' watcher", watcher_name); | |
| 29 local ok, err = pcall(watcher, runner, ...); -- COMPAT: Switch to xpcall after Lua 5.1 | |
| 30 if not ok then | |
| 31 runner:log("error", "Error in '%s' watcher: %s", watcher_name, err); | |
| 32 return nil, err; | |
| 33 end | |
| 34 return true; | |
| 10 end | 35 end |
| 11 | 36 |
| 12 local function runner_continue(thread) | 37 local function runner_continue(thread) |
| 13 -- ASSUMPTION: runner is in 'waiting' state (but we don't have the runner to know for sure) | 38 -- ASSUMPTION: runner is in 'waiting' state (but we don't have the runner to know for sure) |
| 14 if coroutine.status(thread) ~= "suspended" then -- This should suffice | 39 if coroutine.status(thread) ~= "suspended" then -- This should suffice |
| 18 local ok, state, runner = coroutine.resume(thread); | 43 local ok, state, runner = coroutine.resume(thread); |
| 19 if not ok then | 44 if not ok then |
| 20 local err = state; | 45 local err = state; |
| 21 -- Running the coroutine failed, which means we have to find the runner manually, | 46 -- Running the coroutine failed, which means we have to find the runner manually, |
| 22 -- in order to inform the error handler | 47 -- in order to inform the error handler |
| 23 local level = 0; | 48 runner = runner_from_thread(thread); |
| 24 -- Find the 'level' of the top-most function (0 == current level, 1 == caller, ...) | 49 if not runner then |
| 25 while debug.getinfo(thread, level, "") do level = level + 1; end | 50 log("warn", "unexpected async state: unable to locate runner during error handling"); |
| 26 ok, runner = debug.getlocal(thread, level-1, 1); | |
| 27 if ok ~= "self" or runner.thread ~= thread then | |
| 28 log("warn", "unexpected async state: unable to locate runner during error handling, got %s", ok); | |
| 29 return false; | 51 return false; |
| 30 end | 52 end |
| 31 local error_handler = runner.watchers.error; | 53 call_watcher(runner, "error", debug.traceback(thread, err)); |
| 32 if error_handler then error_handler(runner, debug.traceback(thread, err)); end | |
| 33 runner.state, runner.thread = "ready", nil; | 54 runner.state, runner.thread = "ready", nil; |
| 34 return runner:run(); | 55 return runner:run(); |
| 35 elseif state == "ready" then | 56 elseif state == "ready" then |
| 36 -- If state is 'ready', it is our responsibility to update runner.state from 'waiting'. | 57 -- If state is 'ready', it is our responsibility to update runner.state from 'waiting'. |
| 37 -- We also have to :run(), because the queue might have further items that will not be | 58 -- We also have to :run(), because the queue might have further items that will not be |
