142 lines
2.9 KiB
Lua
142 lines
2.9 KiB
Lua
local process = {}
|
|
|
|
function process.sleep(time)
|
|
time = time or 0
|
|
local t = os.startTimer(time)
|
|
local start = os.clock()
|
|
local ev, arg, tdiff
|
|
|
|
repeat
|
|
ev, arg = os.pullEvent()
|
|
tdiff = os.clock() - start
|
|
until (ev == "timer" and arg == t) or tdiff > time
|
|
end
|
|
|
|
process.signals = {
|
|
HALT = 0,
|
|
RESUME = 1,
|
|
TERM = 2,
|
|
KILL = 3
|
|
}
|
|
|
|
process.status = {
|
|
ALIVE = 0,
|
|
DEAD = 1,
|
|
HALTED = 2,
|
|
ERRORED = 3
|
|
}
|
|
|
|
process.processes = {}
|
|
|
|
local nextID = 0
|
|
function process.spawn(fn,err)
|
|
if err==_G.error then err = nil end
|
|
local thisID = nextID
|
|
nextID = nextID + 1
|
|
local proc = {
|
|
co = coroutine.create(fn),
|
|
err = err or function(e,p) error(e) end,
|
|
id = thisID,
|
|
status = process.status.ALIVE
|
|
}
|
|
process.processes[proc.id]=proc
|
|
process.tick(proc,{}) -- empty tick
|
|
return proc.id
|
|
end
|
|
|
|
function process.reset()
|
|
process.processes = {}
|
|
nextID = 0
|
|
end
|
|
|
|
function process.tick(proc,event)
|
|
if type(proc)~='table' then return false end
|
|
if proc.status ~= process.status.ALIVE then return false end
|
|
if proc.filter~=nil and proc.filter~=event[1] then
|
|
if event[1]~="terminate" then
|
|
return process.isRunning(proc.id)
|
|
end
|
|
end
|
|
local ok,err = coroutine.resume(proc.co,table.unpack(event))
|
|
if not ok then
|
|
proc.err(err,proc)
|
|
proc.status = process.status.DEAD
|
|
else
|
|
proc.filter = err
|
|
end
|
|
if coroutine.status(proc.co)=="dead" then
|
|
proc.status = process.status.DEAD
|
|
return false
|
|
end
|
|
return true
|
|
end
|
|
|
|
function process.get(id)
|
|
return process.processes[id]
|
|
end
|
|
|
|
function process.isRunning(id)
|
|
return process.get(id).status == process.status.ALIVE
|
|
end
|
|
|
|
function process.hasActive()
|
|
for i=0,(nextID-1) do
|
|
if process.get(i) and process.isRunning(i) then return true end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function process.getActive()
|
|
ret = {}
|
|
for i=0,(nextID-1) do
|
|
if process.get(i) and process.isRunning(i) then table.insert(ret,i) end
|
|
end
|
|
return ret
|
|
end
|
|
|
|
|
|
local function apply_signal(proc,sig)
|
|
process.tick(proc,{"signal",sig})
|
|
if sig==process.signals.HALT and process.isRunning(proc.id) then
|
|
proc.status = process.status.HALTED
|
|
end
|
|
if sig==process.signals.RESUME and proc.status==process.status.HALTED then
|
|
proc.status = process.status.ALIVE
|
|
end
|
|
if sig==process.signals.TERM and process.isRunning(proc.id) then
|
|
process.tick(proc,{"terminate"})
|
|
end
|
|
if sig==process.signals.KILL and process.isRunning(proc.id) then
|
|
proc.status = process.status.DEAD
|
|
end
|
|
end
|
|
|
|
function process.signal(id,sig)
|
|
if type(sig)=="string" then sig = process.signals[sig] end
|
|
apply_signal(process.get(id),sig)
|
|
end
|
|
|
|
function process.killAll()
|
|
for i=0,(nextID-1) do
|
|
if process.get(i) then
|
|
process.signal(i,"TERM")
|
|
if process.isRunning(i) then process.signal(i,"KILL") end
|
|
end
|
|
end
|
|
end
|
|
|
|
for k,v in pairs(process.signals) do
|
|
process[string.lower(k)]=function(id) process.signal(id,v) end
|
|
end
|
|
|
|
function process.loop()
|
|
repeat
|
|
local event = {os.pullEvent()}
|
|
for i=0,(nextID-1) do
|
|
process.tick(process.get(i),event)
|
|
end
|
|
until not process.hasActive()
|
|
end
|
|
|
|
return process
|