mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2025-12-24 00:51:26 +00:00
changes: Rewrote scheduler to use a sorted linked-list to store scheduled tasks so that only one element needs to be checked if none of the tasks are ready to fire. Scheduler now checks tasks every 2 ds. Adding tasks to an empty scheduler or tasks that are triggered after any existing tasks is fast, but adding tasks that trigger between two existing tasks requires iterating through some of the task list. It's no addtimer(), but it's something.
167 lines
4.6 KiB
Plaintext
167 lines
4.6 KiB
Plaintext
/var/datum/controller/process/scheduler/scheduler
|
|
|
|
/************
|
|
* Scheduler *
|
|
************/
|
|
/datum/controller/process/scheduler
|
|
var/list/datum/scheduled_task/tasks = list()
|
|
var/datum/scheduled_task/head
|
|
|
|
/datum/controller/process/scheduler/setup()
|
|
name = "scheduler"
|
|
schedule_interval = 2
|
|
scheduler = src
|
|
|
|
/datum/controller/process/scheduler/doWork()
|
|
while (head && !PSCHED_CHECK_TICK)
|
|
if (head.destroyed)
|
|
head = head.next
|
|
tasks -= head
|
|
head.kill()
|
|
continue
|
|
if (head.trigger_time >= world.time)
|
|
return // Nothing after this will be ready to fire.
|
|
|
|
// This one's ready to fire, process it.
|
|
var/datum/scheduled_task/task = head
|
|
head = task.next
|
|
task.pre_process()
|
|
task.process()
|
|
task.post_process()
|
|
if (task.destroyed) // post_process probably destroyed it.
|
|
tasks -= task
|
|
task.kill()
|
|
|
|
/datum/controller/process/scheduler/proc/queue(datum/scheduled_task/task)
|
|
if (!task || !task.trigger_time)
|
|
warning("scheduler: Invalid task queued! Ignoring.")
|
|
return
|
|
// Reset this in-case we're doing a rebuild.
|
|
task.next = null
|
|
if (!head && !tasks.len)
|
|
head = task
|
|
tasks += task
|
|
return
|
|
|
|
if (!head) // Head's missing but we still have tasks, rebuild.
|
|
tasks += task
|
|
rebuild_queue()
|
|
return
|
|
|
|
var/datum/scheduled_task/curr = head
|
|
while (curr.next && curr.trigger_time < task.trigger_time)
|
|
curr = curr.next
|
|
|
|
if (!curr.next)
|
|
// We're at the end of the queue, just append.
|
|
curr.next = task
|
|
tasks += task
|
|
return
|
|
|
|
// Inserting midway into the list.
|
|
var/old_next = curr.next
|
|
curr.next = task
|
|
task.next = old_next
|
|
tasks += task
|
|
|
|
// Rebuilds the queue linked-list, removing invalid or destroyed entries.
|
|
/datum/controller/process/scheduler/proc/rebuild_queue()
|
|
log_debug("scheduler: Rebuilding queue.")
|
|
var/list/old_tasks = tasks
|
|
tasks = list()
|
|
if (!old_tasks.len)
|
|
log_debug("scheduler: rebuild was called on empty queue! Aborting.")
|
|
return
|
|
|
|
// Find the head.
|
|
for (var/thing in old_tasks)
|
|
var/datum/scheduled_task/task = thing
|
|
if (QDELETED(task))
|
|
old_tasks -= task
|
|
continue
|
|
|
|
if (task.destroyed)
|
|
old_tasks -= task
|
|
task.kill()
|
|
continue
|
|
|
|
if (!head || task.trigger_time < head.trigger_time)
|
|
head = task
|
|
|
|
if (!head)
|
|
log_debug("scheduler: unable to find head! Purging task queue.")
|
|
for (var/thing in old_tasks)
|
|
var/datum/scheduled_task/task = thing
|
|
if (QDELETED(task))
|
|
continue
|
|
|
|
task.kill()
|
|
|
|
head = null
|
|
return
|
|
|
|
// Don't queue the head.
|
|
tasks += head
|
|
old_tasks -= head
|
|
|
|
// Now rebuild the queue.
|
|
for (var/thing in old_tasks)
|
|
var/datum/scheduled_task/task = thing
|
|
|
|
queue(task)
|
|
|
|
log_debug("scheduler: Queue diff is [old_tasks.len - tasks.len].")
|
|
|
|
/datum/controller/process/scheduler/statProcess()
|
|
..()
|
|
stat(null, "[tasks.len] task\s")
|
|
|
|
/datum/controller/process/scheduler/proc/schedule(var/datum/scheduled_task/st)
|
|
queue(st)
|
|
|
|
/datum/controller/process/scheduler/proc/unschedule(var/datum/scheduled_task/st)
|
|
st.destroyed = TRUE
|
|
|
|
/**********
|
|
* Helpers *
|
|
**********/
|
|
/proc/schedule(source, the_proc, time, ...)
|
|
if (time < 0)
|
|
return
|
|
time += world.time
|
|
var/list/the_args
|
|
if (length(args) > 3)
|
|
the_args = args.Copy(4)
|
|
else
|
|
the_args = list()
|
|
if (source)
|
|
return schedule_task_with_source(time, the_proc, the_args)
|
|
else
|
|
return schedule_task(time, the_proc, the_args)
|
|
|
|
/proc/schedule_task_in(var/in_time, var/procedure, var/list/arguments = list())
|
|
return schedule_task(world.time + in_time, procedure, arguments)
|
|
|
|
/proc/schedule_task_with_source_in(var/in_time, var/source, var/procedure, var/list/arguments = list())
|
|
return schedule_task_with_source(world.time + in_time, source, procedure, arguments)
|
|
|
|
/proc/schedule_task(var/trigger_time, var/procedure, var/list/arguments)
|
|
var/datum/scheduled_task/st = new/datum/scheduled_task(trigger_time, procedure, arguments, /proc/destroy_scheduled_task, list())
|
|
scheduler.schedule(st)
|
|
return st
|
|
|
|
/proc/schedule_task_with_source(var/trigger_time, var/source, var/procedure, var/list/arguments)
|
|
var/datum/scheduled_task/st = new/datum/scheduled_task/source(trigger_time, source, procedure, arguments, /proc/destroy_scheduled_task, list())
|
|
scheduler.schedule(st)
|
|
return st
|
|
|
|
/proc/schedule_repeating_task(var/trigger_time, var/repeat_interval, var/procedure, var/list/arguments)
|
|
var/datum/scheduled_task/st = new/datum/scheduled_task(trigger_time, procedure, arguments, /proc/repeat_scheduled_task, list(repeat_interval))
|
|
scheduler.schedule(st)
|
|
return st
|
|
|
|
/proc/schedule_repeating_task_with_source(var/trigger_time, var/repeat_interval, var/source, var/procedure, var/list/arguments)
|
|
var/datum/scheduled_task/st = new/datum/scheduled_task/source(trigger_time, source, procedure, arguments, /proc/repeat_scheduled_task, list(repeat_interval))
|
|
scheduler.schedule(st)
|
|
return st
|