VoxeLibre/mods/CORE/vl_scheduler/init.lua

164 lines
4.4 KiB
Lua

local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname)
vl_scheduler = {}
local mod = vl_scheduler
-- Imports
local call_safe = mcl_util.call_safe
dofile(modpath.."/queue.lua")
dofile(modpath.."/fifo.lua")
dofile(modpath.."/test.lua")
local run_queues = {}
for i = 1,4 do
run_queues[i] = mod.fifo:new()
end
local tasks = 0
local time = 0
local priority_queue = mod.queue:new()
local functions = {}
local function_id_from_name = {}
local unpack = unpack
local minetest_get_us_time = minetest.get_us_time
local queue_add_task = mod.queue.add_task
local queue_get = mod.queue.get
local queue_tick = mod.queue.tick
local fifo_insert = mod.fifo.insert
local fifo_get = mod.fifo.get
function mod.add_task(time, name, priority, args)
if priority then
if priority > 4 then priority = 4 end
if priority < 1 then priority = 1 end
end
local fid = function_id_from_name[name]
if not fid then
print("Trying to add task with unknown function "..name)
return
end
local dtime = math.floor(time * 20) + 1
local task = {
time = dtime, -- Used by scheduler to track how long until this task is dispatched
dtime = dtime, -- Original time amount
fid = fid,
priority = priority,
args = args,
}
queue_add_task(priority_queue, task)
end
function mod.register_function(name, func, default_time, default_priority)
-- Validate module in name
local modname = minetest.get_current_modname()
if string.sub(name,1,#modname+1) ~= (modname..":") and string.sub(name,1) ~= ":" then
error("Module "..modname.." is trying to register function '"..name.."' that doesn't start with either '"..modname..":' or ':'")
end
if string.sub(name,1) == ":" then
name = string.sub(name,2,#name-1)
end
local fid = #functions + 1
functions[fid] = {
func = func,
name = name,
fid = fid,
}
function_id_from_name[name] = fid
print("Registering "..name.." as #"..tostring(fid))
-- Provide a function to easily schedule tasks
local dtime = math.floor((default_time or 0) * 20)+1
if not default_priority then default_priority = 3 end
return function(...)
local task = {
time = dtime,
dtime = dtime,
fid = fid,
priority = default_priority,
args = ...
}
queue_add_task(priority_queue, task)
end
end
-- Examples of scheduler task:
if false then
-- Register a task that runs ever 0.25 seconds
mod.register_function("vl_scheduler:test",function(task)
print("game time="..tostring(minetest.get_gametime()))
-- Reschedule task
task.time = 0.25
return task
end)()
-- Register a function that runs an action at a fixed time in the future
local act = mod.register_function("vl_scheduler:act",function(task,arg1)
print(dump(arg1))
end, 0.15, 1)
act("test")
end
local function run_scheduler(dtime)
if dtime > 0.11 then
minetest.log("warning", "Timestep greater than 110ms("..tostring(math.floor(dtime*1000)).." ms), server lag detected")
end
local start_time = minetest_get_us_time()
local end_time = start_time + 50000
time = time + dtime
-- Add tasks to the run queues
local iter = queue_tick(priority_queue)
while iter do
local task = iter
iter = iter.next
local priority = task.priority or 3
fifo_insert(run_queues[priority], task)
tasks = tasks + 1
end
local task_time = minetest_get_us_time()
--print("Took "..tostring(task_time-start_time).." us to update task list")
-- Run tasks until we run out of timeslice
if tasks > 0 then
local i = 1
while i < 4 and minetest_get_us_time() < end_time do
local task = fifo_get(run_queues[i])
if task then
tasks = tasks - 1
local func = functions[task.fid]
if func then
--print("Running task "..dump(task)..",func="..dump(func))
local ok,ret = call_safe(
"Error while running task "..func.name..": ",
func.func, {task, unpack(task.args or {})}
)
-- If the task was returned, reschedule it
if ret == task then
task.time = math.floor(task.time * 20) + 1
task.next = nil
queue_add_task(priority_queue, task)
end
local next_task_time = minetest_get_us_time()
print(func.name.." took "..(next_task_time-task_time).." us")
task_time = next_task_time
end
else
i = i + 1
end
end
end
--print("Total scheduler time: "..tostring(minetest_get_us_time() - start_time).." microseconds")
--print("priority_queue="..dump(priority_queue))
end
minetest.register_globalstep(function(dtime) run_scheduler(dtime) end)