summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2020-02-05 00:25:21 +0800
committerruki <[email protected]>2020-02-07 22:45:56 +0800
commit4f3d54cfbbfc2f7b7c2db32902af060d295422f6 (patch)
treec276509abdca6b3f34427baabebd4f64841fc72f
parent7cf854042808382beff5e3ceaaa430f8369d980c (diff)
optimize co_group_wait
-rw-r--r--xmake/core/base/scheduler.lua90
1 files changed, 65 insertions, 25 deletions
diff --git a/xmake/core/base/scheduler.lua b/xmake/core/base/scheduler.lua
index 12b3eda3f..a687af1d9 100644
--- a/xmake/core/base/scheduler.lua
+++ b/xmake/core/base/scheduler.lua
@@ -245,6 +245,38 @@ function scheduler:_co_tasks_suspended_cancel_all()
return true
end
+-- resume it's waiting coroutine if all coroutines are dead in group
+function scheduler:_co_groups_resume()
+
+ local resumed_count = 0
+ local co_groups = self._CO_GROUPS
+ if co_groups then
+ for name, co_group in pairs(co_groups) do
+ local count = 0
+ for _, co in ipairs(co_group) do
+ if co:is_dead() then
+ count = count + 1
+ else
+ break
+ end
+ end
+ -- all coroutines are dead in this group?
+ if count > 0 and count == #co_group then
+ -- resume the waiting coroutine of this group
+ local co_waiting = self._CO_GROUPS_WAITING[name]
+ if co_waiting and co_waiting:is_suspended() then
+ local ok, errors = self:co_resume(co_waiting)
+ if not ok then
+ return -1, errors
+ end
+ resumed_count = resumed_count + 1
+ end
+ end
+ end
+ end
+ return resumed_count
+end
+
-- start a new coroutine task
function scheduler:co_start(cotask, ...)
return self:co_start_named(nil, cotask, ...)
@@ -398,10 +430,9 @@ function scheduler:co_group_wait(name)
end
end
if count ~= #co_group then
- local ok, errors = scheduler.co_sleep(self, 100)
- if not ok then
- return false, errors
- end
+ self._CO_GROUPS_WAITING = self._CO_GROUPS_WAITING or {}
+ self._CO_GROUPS_WAITING[name] = running
+ self:co_suspend()
end
until count == #co_group
self._CO_GROUPS[name] = nil
@@ -664,31 +695,40 @@ function scheduler:runloop()
local timeout = -1
while self._STARTED and self:co_count() > 0 do
- -- get the next timeout
- timeout = self:_timer():delay() or 1000
-
- -- wait events
- local count, events = poller:wait(timeout)
- if count < 0 then
+ -- resume it's waiting coroutine if all coroutines are dead in group
+ local resumed_count, resumed_errors = self:_co_groups_resume()
+ if resumed_count < 0 then
ok = false
- errors = events
- break
- end
+ errors = resumed_errors
+ break;
+ elseif resumed_count == 0 then
- -- resume all suspended tasks with events
- for _, e in ipairs(events) do
- local obj = e[1]
- local objevents = e[2]
- local eventfunc = e[3]
- if eventfunc then
- ok, errors = eventfunc(self, obj, objevents)
- if not ok then
- break
+ -- get the next timeout
+ timeout = self:_timer():delay() or 1000
+
+ -- wait events
+ local count, events = poller:wait(timeout)
+ if count < 0 then
+ ok = false
+ errors = events
+ break
+ end
+
+ -- resume all suspended tasks with events
+ for _, e in ipairs(events) do
+ local obj = e[1]
+ local objevents = e[2]
+ local eventfunc = e[3]
+ if eventfunc then
+ ok, errors = eventfunc(self, obj, objevents)
+ if not ok then
+ break
+ end
end
end
- end
- if not ok then
- break
+ if not ok then
+ break
+ end
end
-- spank the timer and trigger all timeout tasks