diff options
| author | ruki <[email protected]> | 2019-11-29 21:00:08 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2019-11-29 00:00:49 +0800 |
| commit | 3684e6e787a021555f33b5cc6731815507e897ee (patch) | |
| tree | d4659f45a8dd41db8d25d4c813810a35ee92113e | |
| parent | 6e42cbc962f56c1e841f66cfda0e4c8f8cde787a (diff) | |
add coroutine instance for scheduler
| -rw-r--r-- | xmake/actions/run/xmake.lua | 2 | ||||
| -rw-r--r-- | xmake/core/base/scheduler.lua | 187 | ||||
| -rw-r--r-- | xmake/core/base/socket.lua | 4 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/core/base/scheduler.lua | 11 | ||||
| -rw-r--r-- | xmake/plugins/lua/xmake.lua | 8 |
5 files changed, 177 insertions, 35 deletions
diff --git a/xmake/actions/run/xmake.lua b/xmake/actions/run/xmake.lua index 791106662..b7760d89b 100644 --- a/xmake/actions/run/xmake.lua +++ b/xmake/actions/run/xmake.lua @@ -43,7 +43,7 @@ task("run") { {'d', "debug", "k", nil, "Run and debug the given target." } , {'a', "all", "k", nil, "Run all targets." } - , {'w', "workdir", "kv", nil, "Work directory of runing targets, default is folder of targetfile", + , {'w', "workdir", "kv", nil, "Work directory of running targets, default is folder of targetfile", "e.g.", " --workdir=.", " --workdir=`pwd`" } diff --git a/xmake/core/base/scheduler.lua b/xmake/core/base/scheduler.lua index b0f50f963..2138caf1e 100644 --- a/xmake/core/base/scheduler.lua +++ b/xmake/core/base/scheduler.lua @@ -19,43 +19,160 @@ -- -- define module: scheduler -local scheduler = scheduler or {} +local scheduler = scheduler or {} +local _coroutine = _coroutine or {} -- load modules +local dlist = require("base/dlist") local table = require("base/table") local option = require("base/option") local string = require("base/string") local coroutine = require("base/coroutine") +-- new a coroutine instance +function _coroutine.new(rawco) + local instance = table.inherit(_coroutine) + instance._RAWCO = rawco + setmetatable(instance, _coroutine) + return instance +end + +-- get the coroutine name +function _coroutine:name() + return self._NAME or "none" +end + +-- set the coroutine name +function _coroutine:name_set(name) + self._NAME = name +end + +-- get the raw coroutine thread +function _coroutine:rawco() + return self._RAWCO +end + +-- get the coroutine status +function _coroutine:status() + return coroutine.status(self:rawco()) +end + +-- is dead? +function _coroutine:is_dead() + return self:status() == "dead" +end + +-- is running? +function _coroutine:is_running() + return self:status() == "running" +end + +-- is suspended? +function _coroutine:is_suspended() + return self:status() == "suspended" +end + +-- resume the coroutine +function _coroutine:resume(...) + return coroutine.resume(self:rawco(), ...) +end + +-- yield the coroutine +function _coroutine:yield(...) + return coroutine.yield(self:rawco(), ...) +end + +-- tostring(socket) +function _coroutine:__tostring() + return string.format("<co: %s/%s>", self:rawco(), self:name()) +end + +-- gc(coroutine) +function _coroutine:__gc() + self._RAWCO = nil +end + -- TODO we need support socket/pipe io and processes as same time -function scheduler:_co_poller_loop() +function scheduler:_poller_loop() print("poller loop") end --- get all ready coroutines +-- ensure to start the poller loop +function scheduler:_poller_loop_ensure() + + -- ensure to run on coroutine with scheduler + if not self:running() then + return false, "please wait events on coroutine with scheduler!" + end + + -- start the poller loop + if not self._POLLER_STARTED then + local co, errors = self:run(self._poller_loop, self) + if not co then + return false, "start poller loop failed!" + end + co:name_set("poller_loop") + self._POLLER_STARTED = true + end + return true +end + +-- start scheduler loop +function scheduler:_startloop() + self._RUNNING = true + self._POLLER_STARTED = false +end + +-- stop scheduler loop +function scheduler:_stoploop() + self._RUNNING = false + self._POLLER_STARTED = false +end + +-- create the coroutine instance +function scheduler:_co_create(func) + local rawco = coroutine.create(func) + if not rawco then + return nil, "create coroutine failed!" + end + return _coroutine.new(rawco) +end + +-- TODO +-- suspend the current coroutine +function scheduler:_co_suspend() + coroutine.yield() +end + +-- TODO +-- resume the given coroutine +function scheduler:_co_resume() +end + +-- get all ready coroutines list -- -- ready: ready -> ready -> .. -> running -> .. -> ready -> ..-> -- | | -- ---------------------------<------------------------ -- -function scheduler:_coroutines_ready() - local coroutines_ready = self._COROUTINES_READY - if not coroutines_ready then - coroutines_ready = {} - self._COROUTINES_READY = coroutines_ready +function scheduler:_co_list_ready() + local co_list_ready = self._CO_LIST_READY + if not co_list_ready then + co_list_ready = dlist() + self._CO_LIST_READY = co_list_ready end - return coroutines_ready + return co_list_ready end -- run new coroutine function, it will insert to the pending queue function scheduler:run(func, ...) local argv = table.pack(...) - local co = coroutine.create(function () return func(table.unpack(argv)) end) + local co, errors = self:_co_create(function () return func(table.unpack(argv)) end) if not co then - return false, "create coroutine failed!" + return nil, errors end - table.insert(self:_coroutines_ready(), co) - return true + self:_co_list_ready():push(co) + return co end -- get the current running coroutine in scheduler @@ -63,18 +180,34 @@ function scheduler:running() return self._RUNNING and coroutine.running() or nil end --- wait socket/pipe and process events -function scheduler:wait(object, events, timeout) +-- wait socket events +function scheduler:waitsock(sock, events, timeout) - -- ensure to run on coroutine with scheduler - if not self:running() then - return -1, "please wait events on coroutine with scheduler!" + -- ensure the poller loop + local ok, errors = self:_poller_loop_ensure() + if not ok then + return -1, errors end -- TODO + self:_co_suspend() + return 0 +end + +-- sleep some times (ms) +function scheduler:sleep(ms) + + -- ensure the poller loop + local ok, errors = self:_poller_loop_ensure() + if not ok then + return false, errors + end + + -- TODO + self:_co_suspend() + return true end --- TODO -- run loop, schedule coroutine with socket/io and sub-processes function scheduler:runloop(opt) @@ -84,29 +217,29 @@ function scheduler:runloop(opt) end -- start scheduler - self._RUNNING = true + self:_startloop() -- run loop - local coroutines_ready = self:_coroutines_ready() - while #coroutines_ready > 0 do + local co_list_ready = self:_co_list_ready() + while co_list_ready:size() > 0 do -- get the first ready coroutine - local co_ready = coroutines_ready[1] + local co_ready = co_list_ready:first() -- switch to this coroutine - local ok, result_or_errors = coroutine.resume(co_ready) + local ok, result_or_errors = co_ready:resume() if not ok then return false, result_or_errors end -- this coroutine has been finished? we remove it from the ready queue - if coroutine.status(co_ready) == "dead" then - table.remove(coroutines_ready, 1) + if co_ready:is_dead() then + co_list_ready:shift() end end -- stop scheduler - self._RUNNING = false + self:_stoploop() return true end diff --git a/xmake/core/base/socket.lua b/xmake/core/base/socket.lua index 1dbc9f7da..f86ca9bc1 100644 --- a/xmake/core/base/socket.lua +++ b/xmake/core/base/socket.lua @@ -476,8 +476,8 @@ function _instance:wait(events, timeout) -- wait events local events = -1 local errors = nil - if scheduler.runing() then - events, errors = scheduler.wait(self._SOCK, events, timeout or -1) + if scheduler:running() then + events, errors = scheduler:waitsock(self._SOCK, events, timeout or -1) else events, errors = io.socket_wait(self._SOCK, events, timeout or -1) end diff --git a/xmake/core/sandbox/modules/import/core/base/scheduler.lua b/xmake/core/sandbox/modules/import/core/base/scheduler.lua index eacedc074..282f1490b 100644 --- a/xmake/core/sandbox/modules/import/core/base/scheduler.lua +++ b/xmake/core/sandbox/modules/import/core/base/scheduler.lua @@ -27,7 +27,16 @@ local raise = require("sandbox/modules/raise") -- run a new coroutine function function sandbox_core_base_scheduler.run(func, ...) - local ok, errors = scheduler:run(func, ...) + local co, errors = scheduler:run(func, ...) + if not co then + raise(errors) + end + return co +end + +-- sleep some times (ms) +function sandbox_core_base_scheduler.sleep(ms) + local ok, errors = scheduler:sleep(ms) if not ok then raise(errors) end diff --git a/xmake/plugins/lua/xmake.lua b/xmake/plugins/lua/xmake.lua index dc5e56e67..a9135aa1b 100644 --- a/xmake/plugins/lua/xmake.lua +++ b/xmake/plugins/lua/xmake.lua @@ -57,13 +57,13 @@ task("lua") if path.extension(script) == ".lua" and os.isfile(script) then -- run the given lua script file (xmake lua /tmp/script.lua) - vprint("runing given lua script file: %s", path.relative(script)) + vprint("running given lua script file: %s", path.relative(script)) import(path.basename(script), {rootdir = path.directory(script), anonymous = true})(unpack(option.get("arguments") or {})) elseif os.isfile(path.join(os.scriptdir(), "scripts", script .. ".lua")) then -- run builtin lua script (xmake lua echo "hello xmake") - vprint("runing builtin lua script: %s", script) + vprint("running builtin lua script: %s", script) import("scripts." .. script, {anonymous = true})(unpack(option.get("arguments") or {})) else @@ -78,11 +78,11 @@ task("lua") local result = nil if object then -- run builtin modules (xmake lua core.xxx.xxx) - vprint("runing builtin module: %s", script) + vprint("running builtin module: %s", script) result = object(unpack(option.get("arguments") or {})) else -- run imported modules (xmake lua core.xxx.xxx) - vprint("runing imported module: %s", script) + vprint("running imported module: %s", script) result = import(script, {anonymous = true})(unpack(option.get("arguments") or {})) end if result ~= nil then utils.dump(result) end |
