summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2025-11-21 22:35:40 +0800
committerruki <[email protected]>2025-11-21 11:28:51 +0800
commit3358ae8da2fab205edf2cf0d0bf9bf6332a15479 (patch)
tree257065d0f038b4a70c08b571f262cfa27c4fe4c2
parentb793f5dd2ab1a6fdfaa862a2c2ffc99f06c1c8b5 (diff)
improve runjobs
-rw-r--r--xmake/modules/async/runjobs.lua135
1 files changed, 73 insertions, 62 deletions
diff --git a/xmake/modules/async/runjobs.lua b/xmake/modules/async/runjobs.lua
index 5a5c73db3..6fc316f28 100644
--- a/xmake/modules/async/runjobs.lua
+++ b/xmake/modules/async/runjobs.lua
@@ -193,6 +193,75 @@ function _restore_isolated_environments(state, opt)
end
end
+-- run jobs and wait for completion
+function _run_jobs(state, name, opt)
+ local distcc = opt.distcc
+ state.abort = false
+ state.abort_errors = nil
+ state.finished_count = 0
+ state.curdir = opt.curdir
+ state.waiting_count = 0
+ state.distcc_waiting_count = 0
+ scheduler.co_group_begin(state.group_name, function (co_group)
+ state.semaphore = scheduler.co_semaphore(state.group_name, 0)
+ if distcc then
+ state.distcc_semaphore = scheduler.co_semaphore(state.group_name .. "/distcc", 0)
+ end
+ -- @note we can set `remote_only = true` to run all jobs in remote only
+ local local_comax = 0
+ if not opt.remote_only then
+ local_comax = math.min(state.total, state.comax)
+ for id = 1, local_comax do
+ scheduler.co_start_withopt({name = name .. '/' .. tostring(id), isolate = opt.isolate}, _consume_jobs_loop, state, false)
+ end
+ end
+ if distcc then
+ local left_comax = state.total - local_comax
+ local remote_comax = math.min(distcc:freejobs(), left_comax)
+ for id = 1, remote_comax do
+ scheduler.co_start_withopt({name = name .. '/distcc/' .. tostring(id), isolate = opt.isolate}, _consume_jobs_loop, state, true)
+ end
+ end
+ end)
+
+ -- wait all jobs exited
+ scheduler.co_group_wait(state.group_name)
+ state.stop = true
+
+ -- stop all timers and notify them to exit
+ _stop_timers(state)
+
+ -- wait all timer jobs exited
+ _wait_timers(state)
+end
+
+-- cleanup and handle errors after jobs completion
+function _cleanup_jobs(state, opt)
+ -- restore isolated environments
+ _restore_isolated_environments(state, opt)
+
+ -- exit progress
+ _exit_progress(state)
+
+ -- exit waiting indicator
+ _exit_waiting_indicator(state)
+
+ -- do exit callback
+ if opt.on_exit then
+ opt.on_exit(state.abort_errors)
+ end
+
+ -- re-throw abort errors
+ --
+ -- @note we cannot throw it in coroutine,
+ -- because his causes a direct exit from the entire runloop and
+ -- a quick escape from nested try-catch blocks and coroutines groups.
+ -- so we can not catch runjobs errors, e.g. build fails
+ if state.abort then
+ raise(state.abort_errors)
+ end
+end
+
-- the timer loop
function _timer_loop(state)
local timeout = state.timeout
@@ -471,67 +540,9 @@ function main(name, jobs, opt)
-- start all timers
_start_timers(state, name, opt)
- -- run jobs
- local distcc = opt.distcc
- state.abort = false
- state.abort_errors = nil
- state.finished_count = 0
- state.curdir = opt.curdir
- state.waiting_count = 0
- state.distcc_waiting_count = 0
- scheduler.co_group_begin(state.group_name, function (co_group)
- state.semaphore = scheduler.co_semaphore(state.group_name, 0)
- if distcc then
- state.distcc_semaphore = scheduler.co_semaphore(state.group_name .. "/distcc", 0)
- end
- -- @note we can set `remote_only = true` to run all jobs in remote only
- local local_comax = 0
- if not opt.remote_only then
- local_comax = math.min(state.total, state.comax)
- for id = 1, local_comax do
- scheduler.co_start_withopt({name = name .. '/' .. tostring(id), isolate = opt.isolate}, _consume_jobs_loop, state, false)
- end
- end
- if distcc then
- local left_comax = state.total - local_comax
- local remote_comax = math.min(distcc:freejobs(), left_comax)
- for id = 1, remote_comax do
- scheduler.co_start_withopt({name = name .. '/distcc/' .. tostring(id), isolate = opt.isolate}, _consume_jobs_loop, state, true)
- end
- end
- end)
+ -- run jobs and wait for completion
+ _run_jobs(state, name, opt)
- -- wait all jobs exited
- scheduler.co_group_wait(state.group_name)
- state.stop = true
-
- -- stop all timers and notify them to exit
- _stop_timers(state)
-
- -- wait all timer jobs exited
- _wait_timers(state)
-
- -- restore isolated environments
- _restore_isolated_environments(state, opt)
-
- -- exit progress
- _exit_progress(state)
-
- -- exit waiting indicator
- _exit_waiting_indicator(state)
-
- -- do exit callback
- if opt.on_exit then
- opt.on_exit(state.abort_errors)
- end
-
- -- re-throw abort errors
- --
- -- @note we cannot throw it in coroutine,
- -- because his causes a direct exit from the entire runloop and
- -- a quick escape from nested try-catch blocks and coroutines groups.
- -- so we can not catch runjobs errors, e.g. build fails
- if state.abort then
- raise(state.abort_errors)
- end
+ -- cleanup and handle errors
+ _cleanup_jobs(state, opt)
end