diff --git a/mods/CORE/mcl_scheduler/fifo.lua b/mods/CORE/mcl_scheduler/fifo.lua new file mode 100644 index 000000000..5b2b47d35 --- /dev/null +++ b/mods/CORE/mcl_scheduler/fifo.lua @@ -0,0 +1,44 @@ +local mod = mcl_scheduler + +function Class() + local cls = {} + cls.mt = { __index = cls } + function cls:new(...) + local inst = setmetatable({}, cls.mt) + local construct = inst.construct + if construct then inst:construct(...) end + return inst + end + return cls +end + +-- Amoritized O(1) insert/delete functional First In, First Out (FIFO) queue +local fifo = Class() +mod.fifo = fifo +function fifo.insert(node) + node.next = fifo.inbox + fifo.inbox = node.next +end +function fifo.get() + if not fifo.outbox then + -- reverse inbox + local iter = fifo.inbox + fifo.inbox = nil + + while iter do + local i = iter + iter = iter.next + + i.next = fifo.outbox + fifo.outbox = i + end + end + + local res = fifo.outbox + if res then + fifo.outbox = res.next + res.next = nil + end + return res +end + diff --git a/mods/CORE/mcl_scheduler/init.lua b/mods/CORE/mcl_scheduler/init.lua index 1e3adc831..71377c84a 100644 --- a/mods/CORE/mcl_scheduler/init.lua +++ b/mods/CORE/mcl_scheduler/init.lua @@ -5,6 +5,7 @@ mcl_scheduler = {} local mod = mcl_scheduler dofile(modpath.."/queue.lua") +dofile(modpath.."/fifo.lua") function mod.test() local t = mod.queue.new() @@ -35,5 +36,57 @@ function mod.test() end end -mod.test() +local run_queues = {} +for i = 1,4 do + run_queues[i] = mod.fifo:new() +end +local time = 0 +local priority_queue = mod.queue:new() +local functions = {} + +print(dump(run_queues)) + +minetest.register_globalstep(function(dtime) + local start_time = minetest.get_us_time() + time = time + dtime + local limit = 4 + while time > 0.05 and limit > 0 do + -- Add tasks to the run queues + local iter = priority_queue:tick() + while iter do + local task = iter + iter = iter.next + + local priority = task.priority or 3 + run_queues[priority]:insert(task) + end + + -- Run tasks until we run out of timeslice + local i = 1 + while i < 4 and (minetest.get_us_time() - start_time) < 50000 do + local task = run_queues[i]:get() + if task then + print("Running task "..dump(task)) + local func = functions[task.fid] + local cancel = false + if func then + local err + cancel,err = pcall(func, task.dtime, table.unpack(task.args)) + if err then + minetest.log("error","Error while running task: err") + end + end + + -- Add + if task.period and not cancel then + task.time = task.period + priority_queue:add_task(task) + end + end + end + + time = time - 0.05 + limit = limit - 1 + end +end)