#!/usr/bin/lua -- Created by jiaqiang.ye@lnxall.com -- Coroutine based task list for Lua5.1 -- 2023/01/03 local invoker = require "invoker" local tsklua = {} tsklua["tasklist"] = {} tsklua["taskadd"] = function (func, restart) local typn = type(func) if typn ~= "function" then io.stderr:write("Error, function not given.\n") io.stderr:flush() return false end local cofun = coroutine.create(func) typn = type(cofun) if typn ~= "thread" then io.stderr:write("Error, failed to create coroutine.\n") io.stderr:flush() return false end local tlist = tsklua["tasklist"] tlist[#tlist + 1] = { ["cfun"] = cofun, ["ofunc"] = func, ["expire"] = invoker.uptimsec(), ["restart"] = restart and true or false, } tsklua["tasklist"] = tlist return #tlist end local function pick_next_task(tsklist, nowt) local msecond = 0x7FFFFFFF if not nowt then nowt = invoker.uptimsec() end for idx, tsk in ipairs(tsklist) do local sta = coroutine.status(tsk["cfun"]) if sta == "dead" then if tsk["restart"] and type(tsk["ofunc"]) == "function" then tsk["cfun"] = coroutine.create(tsk["ofunc"]) if nowt > tsk["expire"] then tsk["expire"] = nowt end end else if tsk["expire"] <= nowt then return idx end local ms = tsk["expire"] - nowt if ms > 0 and ms < msecond then msecond = ms end end end if msecond == 0x7FFFFFFF then msecond = 10000 end return false, math.floor(msecond) end tsklua["taskloop"] = function (howl, dfunc, funcdata) local nowt = invoker.uptimsec() local initim = nowt local tlist = tsklua["tasklist"] if type(dfunc) ~= "function" then dfunc = nil end while true do local tdx, mdel = pick_next_task(tlist, nowt) if not tdx then -- no task runnable, just sleep enough time if dfunc then dfunc(mdel, funcdata) else invoker.msleep(mdel) end nowt = invoker.uptimsec() else local tsk = tlist[tdx] local okay, mnext = coroutine.resume(tsk["cfun"], tdx) if not okay then io.stderr:write(string.format("Error, failed to resume coroutine: %d\n", tdx)) io.stderr:flush() end nowt = invoker.uptimsec() local typn = type(mnext) if typn ~= "number" or mnext <= 0 then mnext = 30000 -- force task to delay 30 seconds else mnext = math.floor(mnext) end tsk["expire"] = nowt + mnext end tlist = tsklua["tasklist"] if howl and type(howl) == "number" and nowt >= (initim + howl) then -- time up, break out of task loop break end end return true end tsklua["delay"] = function (msec) local idx = coroutine.yield(msec) return idx end return tsklua