summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2019-11-29 21:00:08 +0800
committerruki <[email protected]>2019-11-29 00:00:49 +0800
commit3684e6e787a021555f33b5cc6731815507e897ee (patch)
treed4659f45a8dd41db8d25d4c813810a35ee92113e
parent6e42cbc962f56c1e841f66cfda0e4c8f8cde787a (diff)
add coroutine instance for scheduler
-rw-r--r--xmake/actions/run/xmake.lua2
-rw-r--r--xmake/core/base/scheduler.lua187
-rw-r--r--xmake/core/base/socket.lua4
-rw-r--r--xmake/core/sandbox/modules/import/core/base/scheduler.lua11
-rw-r--r--xmake/plugins/lua/xmake.lua8
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