2024-04-13 19:05:30 +02:00
|
|
|
local modname = minetest.get_current_modname()
|
|
|
|
local modpath = minetest.get_modpath(modname)
|
|
|
|
|
|
|
|
vl_scheduler = {}
|
|
|
|
local mod = vl_scheduler
|
|
|
|
|
2024-04-14 22:35:38 +02:00
|
|
|
-- Imports
|
|
|
|
local call_safe = mcl_util.call_safe
|
|
|
|
|
2024-04-13 19:05:30 +02:00
|
|
|
dofile(modpath.."/queue.lua")
|
|
|
|
dofile(modpath.."/fifo.lua")
|
2024-04-13 23:26:25 +02:00
|
|
|
dofile(modpath.."/test.lua")
|
2024-04-13 19:05:30 +02:00
|
|
|
|
|
|
|
local run_queues = {}
|
|
|
|
for i = 1,4 do
|
|
|
|
run_queues[i] = mod.fifo:new()
|
|
|
|
end
|
2024-04-14 15:11:28 +02:00
|
|
|
local tasks = 0
|
2024-04-13 19:05:30 +02:00
|
|
|
local time = 0
|
|
|
|
local priority_queue = mod.queue:new()
|
|
|
|
local functions = {}
|
2024-04-13 23:26:25 +02:00
|
|
|
local function_id_from_name = {}
|
|
|
|
|
2024-04-14 15:11:28 +02:00
|
|
|
local unpack = unpack
|
2024-04-13 23:26:25 +02:00
|
|
|
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
|
|
|
|
|
2024-04-14 15:11:28 +02:00
|
|
|
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
|
|
|
|
|
2024-04-13 23:26:25 +02:00
|
|
|
local fid = function_id_from_name[name]
|
2024-04-14 15:11:28 +02:00
|
|
|
if not fid then
|
|
|
|
print("Trying to add task with unknown function "..name)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local dtime = math.floor(time * 20) + 1
|
2024-04-13 23:26:25 +02:00
|
|
|
local task = {
|
2024-04-14 15:11:28 +02:00
|
|
|
time = dtime, -- Used by scheduler to track how long until this task is dispatched
|
|
|
|
dtime = dtime, -- Original time amount
|
2024-04-13 23:26:25 +02:00
|
|
|
fid = fid,
|
2024-04-14 15:11:28 +02:00
|
|
|
priority = priority,
|
|
|
|
args = args,
|
2024-04-13 23:26:25 +02:00
|
|
|
}
|
|
|
|
queue_add_task(priority_queue, task)
|
|
|
|
end
|
|
|
|
|
2024-04-14 17:21:46 +02:00
|
|
|
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
|
|
|
|
|
2024-04-13 23:26:25 +02:00
|
|
|
local fid = #functions + 1
|
|
|
|
functions[fid] = {
|
|
|
|
func = func,
|
|
|
|
name = name,
|
|
|
|
fid = fid,
|
|
|
|
}
|
2024-04-14 15:11:28 +02:00
|
|
|
function_id_from_name[name] = fid
|
2024-04-13 23:26:25 +02:00
|
|
|
print("Registering "..name.." as #"..tostring(fid))
|
2024-04-13 19:05:30 +02:00
|
|
|
|
2024-04-14 17:21:46 +02:00
|
|
|
-- 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
|
2024-04-14 15:11:28 +02:00
|
|
|
|
2024-04-14 17:21:46 +02:00
|
|
|
-- 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
|
2024-04-14 15:11:28 +02:00
|
|
|
|
2024-04-14 21:05:05 +02:00
|
|
|
local function run_scheduler(dtime)
|
2024-04-13 23:26:25 +02:00
|
|
|
local start_time = minetest_get_us_time()
|
2024-04-14 15:11:28 +02:00
|
|
|
local end_time = start_time + 50000
|
2024-04-13 19:05:30 +02:00
|
|
|
time = time + dtime
|
|
|
|
|
|
|
|
-- Add tasks to the run queues
|
2024-04-13 23:26:25 +02:00
|
|
|
local iter = queue_tick(priority_queue)
|
2024-04-13 19:05:30 +02:00
|
|
|
while iter do
|
|
|
|
local task = iter
|
|
|
|
iter = iter.next
|
|
|
|
|
|
|
|
local priority = task.priority or 3
|
2024-04-14 15:11:28 +02:00
|
|
|
|
2024-04-13 23:26:25 +02:00
|
|
|
fifo_insert(run_queues[priority], task)
|
2024-04-14 15:11:28 +02:00
|
|
|
tasks = tasks + 1
|
2024-04-13 19:05:30 +02:00
|
|
|
end
|
2024-04-14 15:11:28 +02:00
|
|
|
local task_time = minetest_get_us_time()
|
|
|
|
--print("Took "..tostring(task_time-start_time).." us to update task list")
|
2024-04-13 19:05:30 +02:00
|
|
|
|
|
|
|
-- Run tasks until we run out of timeslice
|
2024-04-14 15:11:28 +02:00
|
|
|
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))
|
2024-04-14 22:35:38 +02:00
|
|
|
local ok,ret = call_safe(
|
|
|
|
"Error while running task "..func.name..": ",
|
|
|
|
func.func, {task, unpack(task.args or {})}
|
|
|
|
)
|
2024-04-13 19:05:30 +02:00
|
|
|
|
2024-04-14 15:11:28 +02:00
|
|
|
-- If the task was returned, reschedule it
|
|
|
|
if ret == task then
|
2024-04-14 17:21:46 +02:00
|
|
|
task.time = math.floor(task.time * 20) + 1
|
2024-04-14 15:11:28 +02:00
|
|
|
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
|
2024-04-13 19:05:30 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2024-04-14 21:05:05 +02:00
|
|
|
--print("Total scheduler time: "..tostring(minetest_get_us_time() - start_time).." microseconds")
|
2024-04-14 15:11:28 +02:00
|
|
|
--print("priority_queue="..dump(priority_queue))
|
2024-04-14 21:05:05 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
minetest.register_globalstep(function(dtime) run_scheduler(dtime) end)
|
2024-04-13 19:05:30 +02:00
|
|
|
|