summaryrefslogtreecommitdiff
path: root/xmake/modules/private
diff options
context:
space:
mode:
authorruki <[email protected]>2024-04-08 23:06:48 +0800
committerruki <[email protected]>2024-04-08 23:06:48 +0800
commit14f497e354aa9ec61f54e201d4db211da4d2086f (patch)
tree9518e3c939f64bad7bd9e0e67c040642514c9af3 /xmake/modules/private
parentb1f552fae364bcc48884b9f3f8d1d52a0531e92e (diff)
improve jobpool
Diffstat (limited to 'xmake/modules/private')
-rw-r--r--xmake/modules/private/async/jobpool.lua123
1 files changed, 94 insertions, 29 deletions
diff --git a/xmake/modules/private/async/jobpool.lua b/xmake/modules/private/async/jobpool.lua
index 10fe90bbe..51c76847f 100644
--- a/xmake/modules/private/async/jobpool.lua
+++ b/xmake/modules/private/async/jobpool.lua
@@ -24,7 +24,12 @@ import("core.base.list")
import("core.base.hashset")
-- define module
-local jobpool = jobpool or object {_init = {"_size", "_rootjob", "_leafjobs", "_poprefs"}}
+local jobpool = jobpool or object {_init = {"_size", "_rootjob", "_leafjobs"}}
+
+-- the job status
+local JOB_STATUS_FREE = 1
+local JOB_STATUS_PENDING = 2
+local JOB_STATUS_FINISHED = 3
-- get jobs size
function jobpool:size()
@@ -46,7 +51,7 @@ end
--
function jobpool:newjob(name, run, opt)
opt = opt or {}
- return {name = name, run = run, distcc = opt.distcc}
+ return {name = name, run = run, distcc = opt.distcc, status = JOB_STATUS_FREE}
end
-- add run job to the given job node
@@ -61,7 +66,7 @@ end
--
function jobpool:addjob(name, run, opt)
opt = opt or {}
- return self:add({name = name, run = run, distcc = opt.distcc}, opt.rootjob)
+ return self:add({name = name, run = run, distcc = opt.distcc, status = JOB_STATUS_FREE}, opt.rootjob)
end
-- add job to the given job node
@@ -96,27 +101,80 @@ function jobpool:add(job, rootjob)
return job
end
--- pop job without deps at leaf node
-function jobpool:pop()
+-- has free jobs?
+function jobpool:hasfree()
+ if self:size() == 0 then
+ return
+ end
+
+ -- peak a free job from the leaf jobs
+ local leafjobs = self:_getleafjobs()
+ if not leafjobs:empty() then
+ if self._nextfree then
+ return true
+ end
+ local job = leafjobs:last()
+ while job ~= nil do
+ local prevjob = leafjobs:prev(job)
+ if self:_isfree(job) then
+ self._nextfree = job
+ return true
+ elseif job.group or job.status == JOB_STATUS_FINISHED then
+ self:remove(job)
+ end
+ job = prevjob
+ end
+ end
+end
- -- no jobs?
+-- get a free job from the leaf jobs
+function jobpool:getfree()
if self:size() == 0 then
return
end
- -- init leaf jobs first
- local leafjobs = self._leafjobs
- if leafjobs:empty() then
- local refs = {}
- self:_genleafjobs(self:rootjob(), leafjobs, refs)
+ -- get a free job from the leaf jobs
+ local leafjobs = self:_getleafjobs()
+ if not leafjobs:empty() then
+ if self._nextfree then
+ local job = self._nextfree
+ local nextfree = leafjobs:prev(job)
+ if nextfree ~= job and self:_isfree(nextfree) then
+ self._nextfree = nextfree
+ else
+ self._nextfree = nil
+ end
+ job.status = JOB_STATUS_PENDING
+ return job
+ end
+ local job = leafjobs:last()
+ while job ~= nil do
+ local prevjob = leafjobs:prev(job)
+ if self:_isfree(job) then
+ local nextfree = prevjob
+ if nextfree ~= job and self:_isfree(nextfree) then
+ self._nextfree = nextfree
+ end
+ job.status = JOB_STATUS_PENDING
+ return job
+ elseif job.group or job.status == JOB_STATUS_FINISHED then
+ self:remove(job)
+ end
+ job = prevjob
+ end
end
+end
- -- pop a job from the leaf jobs
+-- remove the given job from the leaf jobs
+function jobpool:remove(job)
+ assert(self:size() > 0)
+ local leafjobs = self:_getleafjobs()
if not leafjobs:empty() then
+ assert(job ~= self._nextfree)
- -- get job
- local job = leafjobs:last()
- leafjobs:remove_last()
+ -- remove this job from leaf jobs
+ job.status = JOB_STATUS_FINISHED
+ leafjobs:remove(job)
-- get parents node
local parents = assert(job._parents, "invalid job without parents node!")
@@ -133,19 +191,6 @@ function jobpool:pop()
end
end
end
-
- -- is group node or referenced node (it has been popped once) ?
- local poprefs = self._poprefs
- local jobkey = tostring(job)
- if job.group or poprefs[jobkey] then
- -- pop the next real job
- return self:pop()
- else
- -- pop this job
- self._size = self._size - 1
- poprefs[jobkey] = true
- return job
- end
end
end
@@ -177,6 +222,26 @@ function jobpool:group_leave()
end
end
+-- is free job?
+-- we need to ignore group node (empty job) and referenced node (finished job)
+function jobpool:_isfree(job)
+ if job and job.status == JOB_STATUS_FREE and not job.group then
+ return true
+ end
+end
+
+-- get leaf jobs
+function jobpool:_getleafjobs()
+ local leafjobs = self._leafjobs
+ if leafjobs == nil then
+ leafjobs = list.new()
+ local refs = {}
+ self:_genleafjobs(self:rootjob(), leafjobs, refs)
+ self._leafjobs = leafjobs
+ end
+ return leafjobs
+end
+
-- generate all leaf jobs from the given job
function jobpool:_genleafjobs(job, leafjobs, refs)
local deps = job._deps
@@ -231,5 +296,5 @@ end
-- new a jobpool
function new()
- return jobpool {0, {name = "root"}, list.new(), {}}
+ return jobpool {0, {name = "root"}, nil}
end