diff options
Diffstat (limited to 'xmake/modules/private/async/jobpool.lua')
| -rw-r--r-- | xmake/modules/private/async/jobpool.lua | 127 |
1 files changed, 91 insertions, 36 deletions
diff --git a/xmake/modules/private/async/jobpool.lua b/xmake/modules/private/async/jobpool.lua index 7f9067343..1358e0e12 100644 --- a/xmake/modules/private/async/jobpool.lua +++ b/xmake/modules/private/async/jobpool.lua @@ -20,10 +20,16 @@ -- imports import("core.base.object") +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() @@ -45,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 @@ -60,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 @@ -95,30 +101,73 @@ function jobpool:add(job, rootjob) return job end --- pop job without deps at leaf node -function jobpool:pop() - - -- 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 == 0 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 + -- try to get next free job fastly + 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 + -- find the next free job + local removed_jobs = {} + for job in leafjobs:ritems() do + if self:_isfree(job) then + local nextfree = leafjobs:prev(job) + 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 + table.insert(removed_jobs, job) + end + end + -- not found? if remove group and referenced node exist, + -- we try to remove them and find the next free job again + if #removed_jobs > 0 then + for _, job in ipairs(removed_jobs) do + self:remove(job) + end + for job in leafjobs:ritems() do + if self:_isfree(job) then + local nextfree = leafjobs:prev(job) + if nextfree ~= job and self:_isfree(nextfree) then + self._nextfree = nextfree + end + job.status = JOB_STATUS_PENDING + return job + end + end + end end +end - -- pop a job from the leaf jobs - if #leafjobs > 0 then +-- 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[#leafjobs] - table.remove(leafjobs, #leafjobs) + -- remove this job from leaf jobs + job.status = JOB_STATUS_FINISHED + leafjobs:remove(job) - -- get priority and parents node - local priority = job._priority or 0 + -- get parents node local parents = assert(job._parents, "invalid job without parents node!") -- update all parents nodes @@ -126,27 +175,13 @@ function jobpool:pop() -- we need to avoid adding it to leafjobs repeatly, it will cause dead-loop when poping group job -- @see https://github.com/xmake-io/xmake/issues/2740 if not p._leaf then - p._priority = math.max(p._priority or 0, priority + 1) p._deps:remove(job) if p._deps:empty() and self._size > 0 then p._leaf = true - table.insert(leafjobs, 1, p) + leafjobs:insert_first(p) 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, priority - end end end @@ -178,6 +213,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 @@ -191,7 +246,7 @@ function jobpool:_genleafjobs(job, leafjobs, refs) end else job._leaf = true - table.insert(leafjobs, job) + leafjobs:insert_last(job) end end @@ -232,5 +287,5 @@ end -- new a jobpool function new() - return jobpool {0, {name = "root"}, {}, {}} + return jobpool {0, {name = "root"}, nil} end |
