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