Created
March 23, 2014 12:30
-
-
Save alexshen/9722467 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/lua | |
--[[ | |
A simple coroutine manager inspired by Unity and the example in <<Python Essential Reference>>. | |
--]] | |
--for debugging coroutine in ZeroBrane | |
--require('mobdebug').coro() | |
__call_mt = {} | |
__task_mt = {} | |
local function new_task(f, ...) | |
local args = { ... } | |
local o = {} | |
o.target = coroutine.create(function() | |
return f(table.unpack(args)) | |
end) | |
o.stack = {} | |
-- return true if running | |
-- return false if stopped | |
o.running = function(self) | |
if type(self.target) == 'thread' then | |
return coroutine.status(self.target) ~= 'dead' | |
else | |
return self.target:running() | |
end | |
end | |
o.push = function(self, f) | |
if type(f) == 'thread' then | |
-- save current coroutine, transfer control to the returned coroutine | |
self:_push(f) | |
elseif getmetatable(f) == __task_mt then | |
-- save current coroutine, transfer control to the returned task | |
self:_push(f) | |
else | |
error('invalid argument') | |
end | |
end | |
o._push = function(self, f) | |
table.insert(self.stack, self.target) | |
self.target = f | |
end | |
o.next = function(self) | |
if #self.stack ~= 0 then | |
self.target = self.stack[#self.stack] | |
self.stack[#self.stack] = nil | |
return true | |
end | |
end | |
o.run = function (self) | |
-- we depend on another task, check if that target is completed | |
if getmetatable(self.target) == __task_mt then | |
if not self.target:running() then | |
return self:next() | |
else | |
return true | |
end | |
else | |
local status, result = coroutine.resume(self.target) | |
-- special call, need return to manager | |
if getmetatable(result) == __call_mt then | |
return result | |
elseif getmetatable(result) == __task_mt then | |
self:_push(result) | |
return true | |
elseif type(result) == 'thread' then | |
self:_push(result) | |
return true | |
elseif coroutine.status(self.target) == 'dead' then | |
return self:next() | |
else | |
return true | |
end | |
end | |
end | |
setmetatable(o, __task_mt) | |
return o | |
end | |
-- start a couroutine and add to current manager | |
function start(f, ...) | |
local o = {} | |
setmetatable(o, __call_mt) | |
o.args = {...} | |
o.call = function(self, mgr, task) | |
task:push(mgr:start(f, table.unpack(self.args))) | |
end | |
return o | |
end | |
function wait_for_seconds(sec) | |
return coroutine.create(function () | |
local end_time = os.clock() + sec | |
while os.clock() < end_time do | |
coroutine.yield() | |
end | |
end) | |
end | |
function yield(res) | |
coroutine.yield(res) | |
end | |
function new_comgr() | |
local o = {} | |
o._tasks = {} | |
o.start = function(self, f, ...) | |
local t = new_task(f, ...) | |
table.insert(self._tasks, t) | |
return t | |
end | |
o.update = function(self) | |
local i = #self._tasks | |
while i > 0 do | |
local res = self._tasks[i]:run() | |
if not res then | |
table.remove(self._tasks, i) | |
elseif getmetatable(res) == __call_mt then | |
res:call(self, self._tasks[i]) | |
end | |
i = i - 1 | |
end | |
end | |
return o | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment