diff --git a/btime.dll b/btime.dll new file mode 100644 index 00000000000..36dcbe3af75 Binary files /dev/null and b/btime.dll differ diff --git a/code/__DEFINES/btime.dm b/code/__DEFINES/btime.dm new file mode 100644 index 00000000000..a80446d441c --- /dev/null +++ b/code/__DEFINES/btime.dm @@ -0,0 +1,18 @@ +// Comment this out if the external btime library is unavailable +#define PRECISE_TIMER_AVAILABLE + +#ifdef PRECISE_TIMER_AVAILABLE +var/global/__btime__libName = "btime.[world.system_type==MS_WINDOWS?"dll":"so"]" +#define TimeOfHour (__extern__timeofhour) +#define __extern__timeofhour text2num(call(__btime__libName, "gettime")()) +/hook/startup/proc/checkbtime() + try + // This will always return 1 unless the btime library cannot be accessed + if(TimeOfHour || 1) return 1 + catch(var/exception/e) + world.log << "PRECISE_TIMER_AVAILABLE is defined in btime.dm, but calling the btime library failed: [e]" + world.log << "This is a fatal error. The world will now shut down." + del(world) +#else +#define TimeOfHour (world.timeofday % 36000) +#endif diff --git a/code/controllers/ProcessScheduler/core/_define.dm b/code/__DEFINES/process_scheduler.dm similarity index 63% rename from code/controllers/ProcessScheduler/core/_define.dm rename to code/__DEFINES/process_scheduler.dm index f0165c98708..af859e314ff 100644 --- a/code/controllers/ProcessScheduler/core/_define.dm +++ b/code/__DEFINES/process_scheduler.dm @@ -11,7 +11,9 @@ #define PROCESS_DEFAULT_HANG_ALERT_TIME 600 // 60 seconds #define PROCESS_DEFAULT_HANG_RESTART_TIME 900 // 90 seconds #define PROCESS_DEFAULT_SCHEDULE_INTERVAL 50 // 50 ticks -#define PROCESS_DEFAULT_SLEEP_INTERVAL 2 // 2 ticks -#define PROCESS_DEFAULT_CPU_THRESHOLD 90 // 90% +#define PROCESS_DEFAULT_SLEEP_INTERVAL 8 // 1/8th of a tick -//#define UPDATE_QUEUE_DEBUG \ No newline at end of file +// SCHECK macros +// This references src directly to work around a weird bug with try/catch +#define SCHECK_EVERY(this_many_calls) if(++src.calls_since_last_scheck >= this_many_calls) sleepCheck() +#define SCHECK SCHECK_EVERY(50) diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 5275cd7ca91..b2ddadd7404 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -53,5 +53,3 @@ var/global/list/med_hud_users = list() var/global/list/sec_hud_users = list() var/global/list/antag_hud_users = list() //items that ask to be called every cycle - -var/global/list/active_diseases = list() //Diseases are mob-based, so they get to go here \ No newline at end of file diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm index f465da33c85..cd38e6e34d8 100644 --- a/code/_globalvars/misc.dm +++ b/code/_globalvars/misc.dm @@ -4,9 +4,7 @@ var/global/obj/effect/overlay/slmaster = null // nanomanager, the manager for Nano UIs var/datum/nanomanager/nanomanager = new() // Event Manager, the manager for events. -var/datum/event_manager/event_manager = new() -// Alarm Manager, the manager for alarms. -var/datum/subsystem/alarm/alarm_manager = new() +var/datum/event_manager/event_manager = new() // Announcer intercom, because too much stuff creates an intercom for one message then hard del()s it. var/global/obj/item/device/radio/intercom/global_announcer = create_global_announcer() // Load order issues means this can't be new'd until other code runs diff --git a/code/controllers/ProcessScheduler/ProcessScheduler.dme b/code/controllers/ProcessScheduler/ProcessScheduler.dme deleted file mode 100644 index bf17734cc28..00000000000 --- a/code/controllers/ProcessScheduler/ProcessScheduler.dme +++ /dev/null @@ -1,32 +0,0 @@ -// DM Environment file for ProcessScheduler.dme. -// All manual changes should be made outside the BEGIN_ and END_ blocks. -// New source code should be placed in .dm files: choose File/New --> Code File. - -// BEGIN_INTERNALS -// END_INTERNALS - -// BEGIN_FILE_DIR -#define FILE_DIR . -// END_FILE_DIR - -// BEGIN_PREFERENCES -// END_PREFERENCES - -// BEGIN_INCLUDE -#include "core\_define.dm" -#include "core\_stubs.dm" -#include "core\process.dm" -#include "core\processScheduler.dm" -#include "core\updateQueue.dm" -#include "core\updateQueueWorker.dm" -#include "test\processSchedulerView.dm" -#include "test\testDyingUpdateQueueProcess.dm" -#include "test\testHarness.dm" -#include "test\testHungProcess.dm" -#include "test\testNiceProcess.dm" -#include "test\testSlowProcess.dm" -#include "test\testUpdateQueue.dm" -#include "test\testUpdateQueueProcess.dm" -#include "test\testZombieProcess.dm" -// END_INCLUDE - diff --git a/code/controllers/ProcessScheduler/core/process.dm b/code/controllers/ProcessScheduler/core/process.dm index 89048113d30..c09b5730b69 100644 --- a/code/controllers/ProcessScheduler/core/process.dm +++ b/code/controllers/ProcessScheduler/core/process.dm @@ -48,7 +48,7 @@ // This controls how often the process will yield (call sleep(0)) while it is running. // Every concurrent process should sleep periodically while running in order to allow other // processes to execute concurrently. - var/tmp/sleep_interval = PROCESS_DEFAULT_SLEEP_INTERVAL + var/tmp/sleep_interval // hang_warning_time - this is the time (in 1/10 seconds) after which the server will begin to show "maybe hung" in the context window var/tmp/hang_warning_time = PROCESS_DEFAULT_HANG_WARNING_TIME @@ -59,20 +59,20 @@ // hang_restart_time - After this much time(in 1/10 seconds), the server will automatically kill and restart the process. var/tmp/hang_restart_time = PROCESS_DEFAULT_HANG_RESTART_TIME - // cpu_threshold - if world.cpu >= cpu_threshold, scheck() will call sleep(1) to defer further work until the next tick. This keeps a process from driving a tick into overtime (causing perceptible lag) - var/tmp/cpu_threshold = PROCESS_DEFAULT_CPU_THRESHOLD - // How many times in the current run has the process deferred work till the next tick? var/tmp/cpu_defer_count = 0 + // How many SCHECKs have been skipped (to limit btime calls) + var/tmp/calls_since_last_scheck = 0 + /** * recordkeeping vars */ - // Records the time (server ticks) at which the process last finished sleeping + // Records the time (1/10s timeofday) at which the process last finished sleeping var/tmp/last_slept = 0 - // Records the time (s-ticks) at which the process last began running + // Records the time (1/10s timeofday) at which the process last began running var/tmp/run_start = 0 // Records the number of times this process has been killed and restarted @@ -85,26 +85,33 @@ var/tmp/last_object -datum/controller/process/New(var/datum/controller/processScheduler/scheduler) + // Counts the number of times an exception has occurred; gets reset after 10 + var/tmp/list/exceptions = list() + + // Number of deciseconds to delay before starting the process + var/start_delay = 0 + +/datum/controller/process/New(var/datum/controller/processScheduler/scheduler) ..() main = scheduler previousStatus = "idle" idle() name = "process" schedule_interval = 50 - sleep_interval = 2 + sleep_interval = world.tick_lag / PROCESS_DEFAULT_SLEEP_INTERVAL last_slept = 0 run_start = 0 ticks = 0 last_task = 0 last_object = null -datum/controller/process/proc/started() +/datum/controller/process/proc/started() + var/timeofhour = TimeOfHour // Initialize last_slept so we can know when to sleep - last_slept = world.timeofday + last_slept = timeofhour // Initialize run_start so we can detect hung processes. - run_start = world.timeofday + run_start = timeofhour // Initialize defer count cpu_defer_count = 0 @@ -114,65 +121,65 @@ datum/controller/process/proc/started() onStart() -datum/controller/process/proc/finished() +/datum/controller/process/proc/finished() ticks++ idle() main.processFinished(src) onFinish() -datum/controller/process/proc/doWork() +/datum/controller/process/proc/doWork() -datum/controller/process/proc/setup() +/datum/controller/process/proc/setup() -datum/controller/process/proc/process() +/datum/controller/process/proc/process() started() doWork() finished() -datum/controller/process/proc/running() +/datum/controller/process/proc/running() idle = 0 queued = 0 running = 1 hung = 0 setStatus(PROCESS_STATUS_RUNNING) -datum/controller/process/proc/idle() +/datum/controller/process/proc/idle() queued = 0 running = 0 idle = 1 hung = 0 setStatus(PROCESS_STATUS_IDLE) -datum/controller/process/proc/queued() +/datum/controller/process/proc/queued() idle = 0 running = 0 queued = 1 hung = 0 setStatus(PROCESS_STATUS_QUEUED) -datum/controller/process/proc/hung() +/datum/controller/process/proc/hung() hung = 1 setStatus(PROCESS_STATUS_HUNG) -datum/controller/process/proc/handleHung() +/datum/controller/process/proc/handleHung() + var/timeofhour = TimeOfHour var/datum/lastObj = last_object var/lastObjType = "null" if(istype(lastObj)) lastObjType = lastObj.type - // If world.timeofday has rolled over, then we need to adjust. - if (world.timeofday < run_start) - run_start -= 864000 - - var/msg = "[name] process hung at tick #[ticks]. Process was unresponsive for [(world.timeofday - run_start) / 10] seconds and was restarted. Last task: [last_task]. Last Object Type: [lastObjType]" + // If timeofhour has rolled over, then we need to adjust. + if (timeofhour < run_start) + run_start -= 36000 + var/msg = "[name] process hung at tick #[ticks]. Process was unresponsive for [(timeofhour - run_start) / 10] seconds and was restarted. Last task: [last_task]. Last Object Type: [lastObjType]" logTheThing("debug", null, null, msg) logTheThing("diary", null, null, msg, "debug") message_admins(msg) main.restartProcess(src.name) -datum/controller/process/proc/kill() +/datum/controller/process/proc/kill() if (!killed) var/msg = "[name] process was killed at tick #[ticks]." logTheThing("debug", null, null, msg) @@ -182,60 +189,68 @@ datum/controller/process/proc/kill() // Allow inheritors to clean up if needed onKill() - killed = TRUE - // This should del del(src) -datum/controller/process/proc/scheck(var/tickId = 0) +// Do not call this directly - use SHECK or SCHECK_EVERY +/datum/controller/process/proc/sleepCheck(var/tickId = 0) + calls_since_last_scheck = 0 if (killed) // The kill proc is the only place where killed is set. // The kill proc should have deleted this datum, and all sleeping procs that are // owned by it. CRASH("A killed process is still running somehow...") + if (hung) + // This will only really help if the doWork proc ends up in an infinite loop. + handleHung() + CRASH("Process [name] hung and was restarted.") - // For each tick the process defers, it increments the cpu_defer_count so we don't - // defer indefinitely - if (world.cpu >= cpu_threshold + cpu_defer_count * 10) - sleep(1) + if (main.getCurrentTickElapsedTime() > main.timeAllowance) + sleep(world.tick_lag) cpu_defer_count++ - last_slept = world.timeofday + last_slept = TimeOfHour else - // If world.timeofday has rolled over, then we need to adjust. - if (world.timeofday < last_slept) - last_slept -= 864000 + var/timeofhour = TimeOfHour + // If timeofhour has rolled over, then we need to adjust. + if (timeofhour < last_slept) + last_slept -= 36000 - if (world.timeofday > last_slept + sleep_interval) - // If we haven't slept in sleep_interval ticks, sleep to allow other work to proceed. + if (timeofhour > last_slept + sleep_interval) + // If we haven't slept in sleep_interval deciseconds, sleep to allow other work to proceed. sleep(0) - last_slept = world.timeofday + last_slept = TimeOfHour -datum/controller/process/proc/update() +/datum/controller/process/proc/update() // Clear delta if(previousStatus != status) setStatus(status) var/elapsedTime = getElapsedTime() - if (elapsedTime > hang_restart_time) + if (hung) + handleHung() + return + else if (elapsedTime > hang_restart_time) hung() else if (elapsedTime > hang_alert_time) setStatus(PROCESS_STATUS_PROBABLY_HUNG) else if (elapsedTime > hang_warning_time) setStatus(PROCESS_STATUS_MAYBE_HUNG) -datum/controller/process/proc/getElapsedTime() - if (world.timeofday < run_start) - return world.timeofday - (run_start - 864000) - return world.timeofday - run_start -datum/controller/process/proc/tickDetail() +/datum/controller/process/proc/getElapsedTime() + var/timeofhour = TimeOfHour + if (timeofhour < run_start) + return timeofhour - (run_start - 36000) + return timeofhour - run_start + +/datum/controller/process/proc/tickDetail() return -datum/controller/process/proc/getContext() +/datum/controller/process/proc/getContext() return "[name][main.averageRunTime(src)][main.last_run_time[src]][main.highest_run_time[src]][ticks]\n" -datum/controller/process/proc/getContextData() +/datum/controller/process/proc/getContextData() return list( "name" = name, "averageRunTime" = main.averageRunTime(src), @@ -247,10 +262,10 @@ datum/controller/process/proc/getContextData() "disabled" = disabled ) -datum/controller/process/proc/getStatus() +/datum/controller/process/proc/getStatus() return status -datum/controller/process/proc/getStatusText(var/s = 0) +/datum/controller/process/proc/getStatusText(var/s = 0) if(!s) s = status switch(s) @@ -269,21 +284,21 @@ datum/controller/process/proc/getStatusText(var/s = 0) else return "UNKNOWN" -datum/controller/process/proc/getPreviousStatus() +/datum/controller/process/proc/getPreviousStatus() return previousStatus -datum/controller/process/proc/getPreviousStatusText() +/datum/controller/process/proc/getPreviousStatusText() return getStatusText(previousStatus) -datum/controller/process/proc/setStatus(var/newStatus) +/datum/controller/process/proc/setStatus(var/newStatus) previousStatus = status status = newStatus -datum/controller/process/proc/setLastTask(var/task, var/object) +/datum/controller/process/proc/setLastTask(var/task, var/object) last_task = task last_object = object -datum/controller/process/proc/_copyStateFrom(var/datum/controller/process/target) +/datum/controller/process/proc/_copyStateFrom(var/datum/controller/process/target) main = target.main name = target.name schedule_interval = target.schedule_interval @@ -296,22 +311,62 @@ datum/controller/process/proc/_copyStateFrom(var/datum/controller/process/target last_object = target.last_object copyStateFrom(target) -datum/controller/process/proc/copyStateFrom(var/datum/controller/process/target) +/datum/controller/process/proc/copyStateFrom(var/datum/controller/process/target) -datum/controller/process/proc/onKill() +/datum/controller/process/proc/onKill() -datum/controller/process/proc/onStart() +/datum/controller/process/proc/onStart() -datum/controller/process/proc/onFinish() +/datum/controller/process/proc/onFinish() -datum/controller/process/proc/disable() +/datum/controller/process/proc/disable() disabled = 1 -datum/controller/process/proc/enable() +/datum/controller/process/proc/enable() disabled = 0 +/datum/controller/process/proc/getAverageRunTime() + return main.averageRunTime(src) /datum/controller/process/proc/getLastRunTime() return main.getProcessLastRunTime(src) +/datum/controller/process/proc/getHighestRunTime() + return main.getProcessHighestRunTime(src) + /datum/controller/process/proc/getTicks() return ticks + +/datum/controller/process/proc/statProcess() + var/averageRunTime = round(getAverageRunTime(), 0.1)/10 + var/lastRunTime = round(getLastRunTime(), 0.1)/10 + var/highestRunTime = round(getHighestRunTime(), 0.1)/10 + stat("[name]", "T#[getTicks()]|AR [averageRunTime]|LR [lastRunTime]|HR [highestRunTime]|D [cpu_defer_count]") + +/datum/controller/process/proc/catchException(var/exception/e, var/thrower) + var/etext = "[e]" + var/eid = "[e]" // Exception ID, for tracking repeated exceptions + var/ptext = "" // "processing..." text, for what was being processed (if known) + if(istype(e)) + etext += " in [e.file], line [e.line]" + eid = "[e.file]:[e.line]" + if(eid in exceptions) + if(exceptions[eid]++ >= 10) + return + else + exceptions[eid] = 1 + if(istype(thrower, /datum)) + var/datum/D = thrower + ptext = " processing [D.type]" + if(istype(thrower, /atom)) + var/atom/A = thrower + ptext += " ([A]) ([A.x],[A.y],[A.z])" + world.log << "\[[time_stamp()]\] Process [name] caught exception[ptext]: [etext]" + if(exceptions[eid] >= 10) + world.log << "This exception will now be ignored for ten minutes." + spawn(6000) + exceptions[eid] = 0 + +/datum/controller/process/proc/catchBadType(var/datum/caught) + if(isnull(caught) || !istype(caught) || !isnull(caught.gcDestroyed)) + return // Only bother with types we can identify and that don't belong + catchException("Type [caught.type] does not belong in process' queue") \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/core/processScheduler.dm b/code/controllers/ProcessScheduler/core/processScheduler.dm index 8bb365b2a7f..4bb34183eb2 100644 --- a/code/controllers/ProcessScheduler/core/processScheduler.dm +++ b/code/controllers/ProcessScheduler/core/processScheduler.dm @@ -17,7 +17,10 @@ var/global/datum/controller/processScheduler/processScheduler // Process name -> process object map var/tmp/datum/controller/process/list/nameToProcessMap = new - // Process last start times + // Process last queued times (world time) + var/tmp/datum/controller/process/list/last_queued = new + + // Process last start times (real time) var/tmp/datum/controller/process/list/last_start = new // Process last run durations @@ -29,8 +32,8 @@ var/global/datum/controller/processScheduler/processScheduler // Process highest run time var/tmp/datum/controller/process/list/highest_run_time = new - // Sleep 1 tick -- This may be too aggressive. - var/tmp/scheduler_sleep_interval = 1 + // How long to sleep between runs (set to tick_lag in New) + var/tmp/scheduler_sleep_interval // Controls whether the scheduler is running or not var/tmp/isRunning = 0 @@ -38,6 +41,25 @@ var/global/datum/controller/processScheduler/processScheduler // Setup for these processes will be deferred until all the other processes are set up. var/tmp/list/deferredSetupList = new + var/tmp/currentTick = 0 + + var/tmp/currentTickStart = 0 + + var/tmp/timeAllowance = 0 + + var/tmp/cpuAverage = 0 + + var/tmp/timeAllowanceMax = 0 + +/datum/controller/processScheduler/New() + ..() + // When the process scheduler is first new'd, tick_lag may be wrong, so these + // get re-initialized when the process scheduler is started. + // (These are kept here for any processes that decide to process before round start) + scheduler_sleep_interval = world.tick_lag + timeAllowance = world.tick_lag * 0.5 + timeAllowanceMax = world.tick_lag + /** * deferSetupFor * @param path processPath @@ -66,11 +88,22 @@ var/global/datum/controller/processScheduler/processScheduler /datum/controller/processScheduler/proc/start() isRunning = 1 + // tick_lag will have been set by now, so re-initialize these + scheduler_sleep_interval = world.tick_lag + timeAllowance = world.tick_lag * 0.5 + timeAllowanceMax = world.tick_lag + updateStartDelays() spawn(0) process() /datum/controller/processScheduler/proc/process() + updateCurrentTickData() + + for(var/i=world.tick_lag,i last_start[p] + p.schedule_interval) + if (world.time >= last_queued[p] + p.schedule_interval) setQueuedProcessState(p) /datum/controller/processScheduler/proc/runQueuedProcesses() @@ -176,6 +201,10 @@ var/global/datum/controller/processScheduler/processScheduler nameToProcessMap[newProcess.name] = newProcess +/datum/controller/processScheduler/proc/updateStartDelays() + for(var/datum/controller/process/p in processes) + if(p.start_delay) + last_queued[p] = world.time - p.start_delay /datum/controller/processScheduler/proc/runProcess(var/datum/controller/process/process) spawn(0) @@ -197,8 +226,6 @@ var/global/datum/controller/processScheduler/processScheduler if (!(process in idle)) idle += process - process.idle() - /datum/controller/processScheduler/proc/setQueuedProcessState(var/datum/controller/process/process) if (process in running) running -= process @@ -218,21 +245,22 @@ var/global/datum/controller/processScheduler/processScheduler if (!(process in running)) running += process - process.running() - /datum/controller/processScheduler/proc/recordStart(var/datum/controller/process/process, var/time = null) if (isnull(time)) - time = world.timeofday - - last_start[process] = time + time = TimeOfHour + last_queued[process] = world.time + last_start[process] = time + else + last_queued[process] = (time == 0 ? 0 : world.time) + last_start[process] = time /datum/controller/processScheduler/proc/recordEnd(var/datum/controller/process/process, var/time = null) if (isnull(time)) - time = world.timeofday + time = TimeOfHour // If world.timeofday has rolled over, then we need to adjust. if (time < last_start[process]) - last_start[process] -= 864000 + last_start[process] -= 36000 var/lastRunTime = time - last_start[process] @@ -273,6 +301,12 @@ var/global/datum/controller/processScheduler/processScheduler return t / c return c +/datum/controller/processScheduler/proc/getProcessLastRunTime(var/datum/controller/process/process) + return last_run_time[process] + +/datum/controller/processScheduler/proc/getProcessHighestRunTime(var/datum/controller/process/process) + return highest_run_time[process] + /datum/controller/processScheduler/proc/getStatusData() var/list/data = new @@ -310,11 +344,39 @@ var/global/datum/controller/processScheduler/processScheduler var/datum/controller/process/process = nameToProcessMap[processName] process.disable() -/datum/controller/processScheduler/proc/getProcess(var/name) - return nameToProcessMap[name] +/datum/controller/processScheduler/proc/getCurrentTickElapsedTime() + if (world.time > currentTick) + updateCurrentTickData() + return 0 + else + return TimeOfHour - currentTickStart -/datum/controller/processScheduler/proc/getProcessLastRunTime(var/datum/controller/process/process) - return last_run_time[process] +/datum/controller/processScheduler/proc/updateCurrentTickData() + if (world.time > currentTick) + // New tick! + currentTick = world.time + currentTickStart = TimeOfHour + updateTimeAllowance() + cpuAverage = (world.cpu + cpuAverage + cpuAverage) / 3 -/datum/controller/processScheduler/proc/getIsRunning() - return isRunning +/datum/controller/processScheduler/proc/updateTimeAllowance() + // Time allowance goes down linearly with world.cpu. + var/tmp/error = cpuAverage - 100 + var/tmp/timeAllowanceDelta = sign(error) * -0.5 * world.tick_lag * max(0, 0.001 * abs(error)) + + //timeAllowance = world.tick_lag * min(1, 0.5 * ((200/max(1,cpuAverage)) - 1)) + timeAllowance = min(timeAllowanceMax, max(0, timeAllowance + timeAllowanceDelta)) + +/datum/controller/processScheduler/proc/sign(var/x) + if (x == 0) + return 1 + return x / abs(x) + +/datum/controller/processScheduler/proc/statProcesses() + if(!isRunning) + stat("Processes", "Scheduler not running") + return + stat("Processes", "[processes.len] (R[running.len]/Q[queued.len]/I[idle.len])") + stat(null, "[round(cpuAverage, 0.1)] CPU, [round(timeAllowance, 0.1)/10] TA") + for(var/datum/controller/process/p in processes) + p.statProcess() diff --git a/code/controllers/ProcessScheduler/core/updateQueue.dm b/code/controllers/ProcessScheduler/core/updateQueue.dm deleted file mode 100644 index 118b6692b5a..00000000000 --- a/code/controllers/ProcessScheduler/core/updateQueue.dm +++ /dev/null @@ -1,127 +0,0 @@ -/** - * updateQueue.dm - */ - -#ifdef UPDATE_QUEUE_DEBUG -#define uq_dbg(text) world << text -#else -#define uq_dbg(text) -#endif -/datum/updateQueue - var/tmp/list/objects - var/tmp/previousStart - var/tmp/procName - var/tmp/list/arguments - var/tmp/datum/updateQueueWorker/currentWorker - var/tmp/workerTimeout - var/tmp/adjustedWorkerTimeout - var/tmp/currentKillCount - var/tmp/totalKillCount - -/datum/updateQueue/New(list/objects = list(), procName = "update", list/arguments = list(), workerTimeout = 2, inplace = 0) - ..() - - uq_dbg("Update queue created.") - - // Init proc allows for recycling the worker. - init(objects = objects, procName = procName, arguments = arguments, workerTimeout = workerTimeout, inplace = inplace) - -/** - * init - * @param list objects objects to update - * @param text procName the proc to call on each item in the object list - * @param list arguments optional arguments to pass to the update proc - * @param number workerTimeout number of ticks to wait for an update to - finish before forking a new update worker - * @param bool inplace whether the updateQueue should make a copy of objects. - the internal list will be modified, so it is usually - a good idea to leave this alone. Default behavior is to - copy. - */ -/datum/updateQueue/proc/init(list/objects = list(), procName = "update", list/arguments = list(), workerTimeout = 2, inplace = 0) - uq_dbg("Update queue initialization started.") - - if (!inplace) - // Make an internal copy of the list so we're not modifying the original. - initList(objects) - else - src.objects = objects - - // Init vars - src.procName = procName - src.arguments = arguments - src.workerTimeout = workerTimeout - - adjustedWorkerTimeout = workerTimeout - currentKillCount = 0 - totalKillCount = 0 - - uq_dbg("Update queue initialization finished. procName = '[procName]'") - -/datum/updateQueue/proc/initList(list/toCopy) - /** - * We will copy the list in reverse order, as our doWork proc - * will access them by popping an element off the end of the list. - * This ends up being quite a lot faster than taking elements off - * the head of the list. - */ - objects = new - - uq_dbg("Copying [toCopy.len] items for processing.") - - for(var/i=toCopy.len,i>0,) - objects.len++ - objects[objects.len] = toCopy[i--] - -/datum/updateQueue/proc/Run() - uq_dbg("Starting run...") - - startWorker() - while (istype(currentWorker) && !currentWorker.finished) - sleep(2) - checkWorker() - - uq_dbg("UpdateQueue completed run.") - -/datum/updateQueue/proc/checkWorker() - if(istype(currentWorker)) - // If world.timeofday has rolled over, then we need to adjust. - if(world.timeofday < currentWorker.lastStart) - currentWorker.lastStart -= 864000 - - if(world.timeofday - currentWorker.lastStart > adjustedWorkerTimeout) - // This worker is a bit slow, let's spawn a new one and kill the old one. - uq_dbg("Current worker is lagging... starting a new one.") - killWorker() - startWorker() - else // No worker! - uq_dbg("update queue ended up without a worker... starting a new one...") - startWorker() - -/datum/updateQueue/proc/startWorker() - // only run the worker if we have objects to work on - if(objects.len) - uq_dbg("Starting worker process.") - - // No need to create a fresh worker if we already have one... - if (istype(currentWorker)) - currentWorker.init(objects, procName, arguments) - else - currentWorker = new(objects, procName, arguments) - currentWorker.start() - else - uq_dbg("Queue is empty. No worker was started.") - currentWorker = null - -/datum/updateQueue/proc/killWorker() - // Kill the worker - currentWorker.kill() - currentWorker = null - // After we kill a worker, yield so that if the worker's been tying up the cpu, other stuff can immediately resume - sleep(-1) - currentKillCount++ - totalKillCount++ - if (currentKillCount >= 3) - uq_dbg("[currentKillCount] workers have been killed with a timeout of [adjustedWorkerTimeout]. Increasing worker timeout to compensate.") - adjustedWorkerTimeout++ - currentKillCount = 0 \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/core/updateQueueWorker.dm b/code/controllers/ProcessScheduler/core/updateQueueWorker.dm deleted file mode 100644 index 39737ef0213..00000000000 --- a/code/controllers/ProcessScheduler/core/updateQueueWorker.dm +++ /dev/null @@ -1,83 +0,0 @@ -datum/updateQueueWorker - var/tmp/list/objects - var/tmp/killed - var/tmp/finished - var/tmp/procName - var/tmp/list/arguments - var/tmp/lastStart - var/tmp/cpuThreshold - -datum/updateQueueWorker/New(var/list/objects, var/procName, var/list/arguments, var/cpuThreshold = 90) - ..() - uq_dbg("updateQueueWorker created.") - - init(objects, procName, arguments, cpuThreshold) - -datum/updateQueueWorker/proc/init(var/list/objects, var/procName, var/list/arguments, var/cpuThreshold = 90) - src.objects = objects - src.procName = procName - src.arguments = arguments - src.cpuThreshold = cpuThreshold - - killed = 0 - finished = 0 - -datum/updateQueueWorker/proc/doWork() - // If there's nothing left to execute or we were killed, mark finished and return. - if (!objects || !objects.len) return finished() - - lastStart = world.timeofday // Absolute number of ticks since the world started up - - var/datum/object = objects[objects.len] // Pull out the object - objects.len-- // Remove the object from the list - - if (istype(object) && !isturf(object) && isnull(object.gcDestroyed)) // We only work with real objects - call(object, procName)(arglist(arguments)) - - // If there's nothing left to execute - // or we were killed while running the above code, mark finished and return. - if (!objects || !objects.len) return finished() - - if (world.cpu > cpuThreshold) - // We don't want to force a tick into overtime! - // If the tick is about to go overtime, spawn the next update to go - // in the next tick. - uq_dbg("tick went into overtime with world.cpu = [world.cpu], deferred next update to next tick [1+(world.time / world.tick_lag)]") - - spawn(1) - doWork() - else - spawn(0) // Execute anonymous function immediately as if we were in a while loop... - doWork() - -datum/updateQueueWorker/proc/finished() - uq_dbg("updateQueueWorker finished.") - /** - * If the worker was killed while it was working on something, it - * should delete itself when it finally finishes working on it. - * Meanwhile, the updateQueue will have proceeded on with the rest of - * the queue. This will also terminate the spawned function that was - * created in the kill() proc. - */ - if(killed) - del(src) - - finished = 1 - -datum/updateQueueWorker/proc/kill() - uq_dbg("updateQueueWorker killed.") - killed = 1 - objects = null - - /** - * If the worker is not done in 30 seconds after it's killed, - * we'll forcibly delete it, causing the anonymous function it was - * running to be terminated. Hasta la vista, baby. - */ - spawn(300) - del(src) - -datum/updateQueueWorker/proc/start() - uq_dbg("updateQueueWorker started.") - spawn(0) - doWork() \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/processScheduler.js b/code/controllers/ProcessScheduler/test/processScheduler.js deleted file mode 100644 index 0a4f111355d..00000000000 --- a/code/controllers/ProcessScheduler/test/processScheduler.js +++ /dev/null @@ -1,56 +0,0 @@ -(function ($) { - function setRef(theRef) { - ref = theRef; - } - - function jax(action, data) { - if (typeof data === 'undefined') - data = {}; - var params = []; - for (var k in data) { - if (data.hasOwnProperty(k)) { - params.push(encodeURIComponent(k) + '=' + encodeURIComponent(data[k])); - } - } - var newLoc = '?src=' + ref + ';action=' + action + ';' + params.join(';'); - window.location = newLoc; - } - - function requestRefresh(e) { - jax("refresh", null); - } - - function handleRefresh(processTable) { - $('#processTable').html(processTable); - initProcessTableButtons(); - } - - function requestKill(e) { - var button = $(e.currentTarget); - jax("kill", {name: button.data("process-name")}); - } - - function requestEnable(e) { - var button = $(e.currentTarget); - jax("enable", {name: button.data("process-name")}); - } - - function requestDisable(e) { - var button = $(e.currentTarget); - jax("disable", {name: button.data("process-name")}); - } - - function initProcessTableButtons() { - $(".kill-btn").on("click", requestKill); - $(".enable-btn").on("click", requestEnable); - $(".disable-btn").on("click", requestDisable); - } - - window.setRef = setRef; - window.handleRefresh = handleRefresh; - - $(function() { - initProcessTableButtons(); - $('#btn-refresh').on("click", requestRefresh); - }); -}(jQuery)); \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/processSchedulerView.dm b/code/controllers/ProcessScheduler/test/processSchedulerView.dm deleted file mode 100644 index ae78b3f0154..00000000000 --- a/code/controllers/ProcessScheduler/test/processSchedulerView.dm +++ /dev/null @@ -1,94 +0,0 @@ -/datum/processSchedulerView - -/datum/processSchedulerView/Topic(href, href_list) - if (!href_list["action"]) - return - - switch (href_list["action"]) - if ("kill") - var/toKill = href_list["name"] - processScheduler.killProcess(toKill) - refreshProcessTable() - if ("enable") - var/toEnable = href_list["name"] - processScheduler.enableProcess(toEnable) - refreshProcessTable() - if ("disable") - var/toDisable = href_list["name"] - processScheduler.disableProcess(toDisable) - refreshProcessTable() - if ("refresh") - refreshProcessTable() - -/datum/processSchedulerView/proc/refreshProcessTable() - windowCall("handleRefresh", getProcessTable()) - -/datum/processSchedulerView/proc/windowCall(var/function, var/data = null) - usr << output(data, "processSchedulerContext.browser:[function]") - -/datum/processSchedulerView/proc/getProcessTable() - var/text = "" - // and the context of each - for (var/list/data in processScheduler.getStatusData()) - text += "" - text += "" - text += "" - text += "" - text += "" - text += "" - text += "" - text += "" - text += "" - text += "" - - text += "
NameAvg(s)Last(s)Highest(s)TickcountTickrateStateAction
[data["name"]][num2text(data["averageRunTime"]/10,3)][num2text(data["lastRunTime"]/10,3)][num2text(data["highestRunTime"]/10,3)][num2text(data["ticks"],4)][data["schedule"]][data["status"]]" - if (data["disabled"]) - text += "" - else - text += "" - text += "
" - return text - -/** - * getContext - * Outputs an interface showing stats for all processes. - */ -/datum/processSchedulerView/proc/getContext() - bootstrap_browse() - usr << browse('processScheduler.js', "file=processScheduler.js;display=0") - - var/text = {" - Process Scheduler Detail - - [bootstrap_includes()] - - - -

Process Scheduler

-
- -
- -

The process scheduler controls [processScheduler.getProcessCount()] loops.

"} - - text += "
" - text += getProcessTable() - text += "
" - - usr << browse(text, "window=processSchedulerContext;size=800x600") - -/datum/processSchedulerView/proc/bootstrap_browse() - usr << browse('bower_components/jquery/dist/jquery.min.js', "file=jquery.min.js;display=0") - usr << browse('bower_components/bootstrap2.3.2/bootstrap/js/bootstrap.min.js', "file=bootstrap.min.js;display=0") - usr << browse('bower_components/bootstrap2.3.2/bootstrap/css/bootstrap.min.css', "file=bootstrap.min.css;display=0") - usr << browse('bower_components/bootstrap2.3.2/bootstrap/img/glyphicons-halflings-white.png', "file=glyphicons-halflings-white.png;display=0") - usr << browse('bower_components/bootstrap2.3.2/bootstrap/img/glyphicons-halflings.png', "file=glyphicons-halflings.png;display=0") - usr << browse('bower_components/json2/json2.js', "file=json2.js;display=0") - -/datum/processSchedulerView/proc/bootstrap_includes() - return {" - - - - - "} diff --git a/code/controllers/ProcessScheduler/test/testDyingUpdateQueueProcess.dm b/code/controllers/ProcessScheduler/test/testDyingUpdateQueueProcess.dm deleted file mode 100644 index d08ec46c7da..00000000000 --- a/code/controllers/ProcessScheduler/test/testDyingUpdateQueueProcess.dm +++ /dev/null @@ -1,27 +0,0 @@ -/** - * testDyingUpdateQueueProcess - * This process is an example of a process using an updateQueue. - * The datums updated by this process behave badly and block the update loop - * by sleeping. If you #define UPDATE_QUEUE_DEBUG, you will see the updateQueue - * killing off its worker processes and spawning new ones to work around slow - * updates. This means that if you have a code path that sleeps for a long time - * in mob.Life once in a blue moon, the mob update loop will not hang. - */ -/datum/slowTestDatum/proc/wackyUpdateProcessName() - sleep(rand(0,20)) // Randomly REALLY slow :| - -/datum/controller/process/testDyingUpdateQueueProcess - var/tmp/datum/updateQueue/updateQueueInstance - var/tmp/list/testDatums = list() - -/datum/controller/process/testDyingUpdateQueueProcess/setup() - name = "Dying UpdateQueue Process" - schedule_interval = 30 // every 3 seconds - updateQueueInstance = new - for(var/i = 1, i < 30, i++) - testDatums.Add(new /datum/slowTestDatum) - -/datum/controller/process/testDyingUpdateQueueProcess/doWork() - updateQueueInstance.init(testDatums, "wackyUpdateProcessName") - updateQueueInstance.Run() - \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/testHarness.dm b/code/controllers/ProcessScheduler/test/testHarness.dm deleted file mode 100644 index 2b5f1dff813..00000000000 --- a/code/controllers/ProcessScheduler/test/testHarness.dm +++ /dev/null @@ -1,35 +0,0 @@ -/* - These are simple defaults for your project. - */ -#define DEBUG - -var/global/datum/processSchedulerView/processSchedulerView - -world - loop_checks = 0 - New() - ..() - processScheduler = new - processSchedulerView = new - -mob - step_size = 8 - - New() - ..() - - - verb - startProcessScheduler() - set name = "Start Process Scheduler" - processScheduler.setup() - processScheduler.start() - - getProcessSchedulerContext() - set name = "Get Process Scheduler Status Panel" - processSchedulerView.getContext() - - runUpdateQueueTests() - set name = "Run Update Queue Testsuite" - var/datum/updateQueueTests/t = new - t.runTests() \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/testHungProcess.dm b/code/controllers/ProcessScheduler/test/testHungProcess.dm deleted file mode 100644 index ced05dd4d70..00000000000 --- a/code/controllers/ProcessScheduler/test/testHungProcess.dm +++ /dev/null @@ -1,15 +0,0 @@ -/** - * testHungProcess - * This process is an example of a simple update loop process that hangs. - */ - -/datum/controller/process/testHungProcess/setup() - name = "Hung Process" - schedule_interval = 30 // every 3 seconds - -/datum/controller/process/testHungProcess/doWork() - sleep(1000) // FUCK - // scheck is also responsible for handling hung processes. If a process - // hangs, and later resumes, but has already been killed by the scheduler, - // scheck will force the process to bail out. - scheck() \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/testNiceProcess.dm b/code/controllers/ProcessScheduler/test/testNiceProcess.dm deleted file mode 100644 index aa921bc62fa..00000000000 --- a/code/controllers/ProcessScheduler/test/testNiceProcess.dm +++ /dev/null @@ -1,13 +0,0 @@ -/** - * testNiceProcess - * This process is an example of a simple update loop process that is - * relatively fast. - */ - -/datum/controller/process/testNiceProcess/setup() - name = "Nice Process" - schedule_interval = 10 // every second - -/datum/controller/process/testNiceProcess/doWork() - sleep(rand(1,5)) // Just to pretend we're doing something - \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/testSlowProcess.dm b/code/controllers/ProcessScheduler/test/testSlowProcess.dm deleted file mode 100644 index b7c9e6e21e8..00000000000 --- a/code/controllers/ProcessScheduler/test/testSlowProcess.dm +++ /dev/null @@ -1,28 +0,0 @@ -/** - * testSlowProcess - * This process is an example of a simple update loop process that is slow. - * The update loop here sleeps inside to provide an example, but if you had - * a computationally intensive loop process that is simply slow, you can use - * scheck() inside the loop to force it to yield periodically according to - * the sleep_interval var. By default, scheck will cause a loop to sleep every - * 2 ticks. - */ - -/datum/controller/process/testSlowProcess/setup() - name = "Slow Process" - schedule_interval = 30 // every 3 seconds - -/datum/controller/process/testSlowProcess/doWork() - // set background = 1 will cause loop constructs to sleep periodically, - // whenever the BYOND scheduler deems it productive to do so. - // This behavior is not always sufficient, nor is it always consistent. - // Rather than leaving it up to the BYOND scheduler, we can control it - // ourselves and leave nothing to the black box. - set background = 1 - - for(var/i=1,i<30,i++) - // Just to pretend we're doing something here - sleep(rand(3, 5)) - - // Forces this loop to yield(sleep) periodically. - scheck() \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/testUpdateQueue.dm b/code/controllers/ProcessScheduler/test/testUpdateQueue.dm deleted file mode 100644 index 07b64e927f3..00000000000 --- a/code/controllers/ProcessScheduler/test/testUpdateQueue.dm +++ /dev/null @@ -1,209 +0,0 @@ -var/global/list/updateQueueTestCount = list() - -/datum/updateQueueTests - var/start - proc - runTests() - world << "Running 9 tests..." - testUpdateQueuePerformance() - sleep(1) - testInplace() - sleep(1) - testInplaceUpdateQueuePerformance() - sleep(1) - testUpdateQueueReinit() - sleep(1) - testCrashingQueue() - sleep(1) - testEmptyQueue() - sleep(1) - testManySlowItemsInQueue() - sleep(1) - testVariableWorkerTimeout() - sleep(1) - testReallySlowItemInQueue() - sleep(1) - world << "Finished!" - - beginTiming() - start = world.time - - endTiming(text) - var/time = (world.time - start) / world.tick_lag - world << {"Performance - [text] - [time] ticks"} - - getCount() - return updateQueueTestCount[updateQueueTestCount.len] - - incrementTestCount() - updateQueueTestCount.len++ - updateQueueTestCount[updateQueueTestCount.len] = 0 - - assertCountEquals(count, text) - assertThat(getCount() == count, text) - - assertCountLessThan(count, text) - assertThat(getCount() < count, text) - - assertCountGreaterThan(count, text) - assertThat(getCount() > count, text) - - assertThat(condition, text) - if (condition) - world << {"PASS: [text]"} - else - world << {"FAIL: [text]"} - - testUpdateQueuePerformance() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=100000,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - - var/datum/updateQueue/uq = new(objs) - - beginTiming() - uq.Run() - endTiming("updating 100000 simple objects") - - assertCountEquals(100000, "test that update queue updates all objects expected") - del(objs) - del(uq) - - testUpdateQueueReinit() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=100,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - - var/datum/updateQueue/uq = new(objs) - uq.Run() - objs = new - - for(var/i=1,i<=100,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - uq.init(objs) - uq.Run() - assertCountEquals(200, "test that update queue reinitializes properly and updates all objects as expected.") - del(objs) - del(uq) - - testInplace() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=100,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - var/datum/updateQueue/uq = new(objects = objs, inplace = 1) - uq.Run() - assertThat(objs.len == 0, "test that update queue inplace option really works inplace") - assertCountEquals(100, "test that inplace update queue updates the right number of objects") - del(objs) - del(uq) - - testInplaceUpdateQueuePerformance() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=100000,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - - var/datum/updateQueue/uq = new(objs) - - beginTiming() - uq.Run() - endTiming("updating 100000 simple objects in place") - del(objs) - del(uq) - - testCrashingQueue() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=10,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - objs.Add(new /datum/uqTestDatum/crasher(updateQueueTestCount.len)) - for(var/i=1,i<=10,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - - var/datum/updateQueue/uq = new(objs) - uq.Run() - assertCountEquals(20, "test that update queue handles crashed update procs OK") - del(objs) - del(uq) - - testEmptyQueue() - incrementTestCount() - var/list/objs = new - var/datum/updateQueue/uq = new(objs) - uq.Run() - assertCountEquals(0, "test that update queue doesn't barf on empty lists") - del(objs) - del(uq) - - testManySlowItemsInQueue() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=30,i++) - objs.Add(new /datum/uqTestDatum/slow(updateQueueTestCount.len)) - var/datum/updateQueue/uq = new(objs) - uq.Run() - assertCountEquals(30, "test that update queue slows down execution if too many objects are slow to update") - del(objs) - del(uq) - - testVariableWorkerTimeout() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=20,i++) - objs.Add(new /datum/uqTestDatum/slow(updateQueueTestCount.len)) - var/datum/updateQueue/uq = new(objs, workerTimeout=6) - uq.Run() - assertCountEquals(20, "test that variable worker timeout works properly") - del(objs) - del(uq) - - testReallySlowItemInQueue() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=10,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - objs.Add(new /datum/uqTestDatum/reallySlow(updateQueueTestCount.len)) - for(var/i=1,i<=10,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - var/datum/updateQueue/uq = new(objs) - uq.Run() - assertCountEquals(20, "test that update queue skips objects that are too slow to update") - del(objs) - del(uq) - - - -datum/uqTestDatum - var/testNum - New(testNum) - ..() - src.testNum = testNum - proc/update() - updateQueueTestCount[testNum]++ - proc/lag(cycles) - set background = 1 - for(var/i=0,iProcessing Geometry..." @@ -37,27 +45,36 @@ var/global/datum/controller/process/air_system/air_master process_super_conductivity() return 1 +/datum/controller/process/air_system/statProcess() + ..() + stat(null, "[last_active] active") + stat(null, "[last_excited] EG|[last_hpd] HPD|[last_asc] ASC|[last_hotspots] Hot") + /datum/controller/process/air_system/proc/process_hotspots() + last_hotspots = hotspots.len for(var/obj/effect/hotspot/H in hotspots) H.process() - scheck() + SCHECK /datum/controller/process/air_system/proc/process_super_conductivity() + last_asc = active_super_conductivity.len for(var/turf/simulated/T in active_super_conductivity) T.super_conduct() - scheck() + SCHECK /datum/controller/process/air_system/proc/process_high_pressure_delta() + last_hpd = high_pressure_delta.len for(var/turf/T in high_pressure_delta) T.high_pressure_movements() T.pressure_difference = 0 - scheck() - high_pressure_delta.len = 0 + SCHECK + high_pressure_delta.Cut() /datum/controller/process/air_system/proc/process_active_turfs() + last_active = active_turfs.len for(var/turf/simulated/T in active_turfs) T.process_cell() - scheck() + SCHECK /datum/controller/process/air_system/proc/remove_from_active(var/turf/simulated/T) if(istype(T)) @@ -101,15 +118,16 @@ var/global/datum/controller/process/air_system/air_master active_turfs |= T /datum/controller/process/air_system/proc/process_excited_groups() + last_excited = excited_groups.len for(var/datum/excited_group/EG in excited_groups) EG.breakdown_cooldown ++ if(EG.breakdown_cooldown == 10) EG.self_breakdown() - scheck() + SCHECK return if(EG.breakdown_cooldown > 20) EG.dismantle() - scheck() + SCHECK /datum/controller/process/air_system/proc/setup_overlays() plmaster = new /obj/effect/overlay() diff --git a/code/controllers/Processes/alarm.dm b/code/controllers/Processes/alarm.dm index 6530df1e135..bf2d501ae7a 100644 --- a/code/controllers/Processes/alarm.dm +++ b/code/controllers/Processes/alarm.dm @@ -1,6 +1,35 @@ +// We manually initialize the alarm handlers instead of looping over all existing types +// to make it possible to write: camera.triggerAlarm() rather than alarm_manager.managers[datum/alarm_handler/camera].triggerAlarm() or a variant thereof. +/var/global/datum/alarm_handler/atmosphere/atmosphere_alarm = new() +/var/global/datum/alarm_handler/camera/camera_alarm = new() +/var/global/datum/alarm_handler/fire/fire_alarm = new() +/var/global/datum/alarm_handler/motion/motion_alarm = new() +/var/global/datum/alarm_handler/power/power_alarm = new() + +// Alarm Manager, the manager for alarms. +var/datum/controller/process/alarm/alarm_manager + +/datum/controller/process/alarm + var/list/datum/alarm/all_handlers + /datum/controller/process/alarm/setup() name = "alarm" schedule_interval = 20 // every 2 seconds + all_handlers = list(atmosphere_alarm, camera_alarm, fire_alarm, motion_alarm, power_alarm) + alarm_manager = src /datum/controller/process/alarm/doWork() - alarm_manager.fire() + for(var/datum/alarm_handler/AH in all_handlers) + AH.process() + +/datum/controller/process/alarm/proc/active_alarms() + var/list/all_alarms = new + for(var/datum/alarm_handler/AH in all_handlers) + var/list/alarms = AH.alarms + all_alarms += alarms + + return all_alarms + +/datum/controller/process/alarm/proc/number_of_active_alarms() + var/list/alarms = active_alarms() + return alarms.len diff --git a/code/controllers/Processes/bot.dm b/code/controllers/Processes/bot.dm index b93324d0901..dceb5504b67 100644 --- a/code/controllers/Processes/bot.dm +++ b/code/controllers/Processes/bot.dm @@ -1,20 +1,27 @@ -/datum/controller/process/bot - var/tmp/datum/updateQueue/updateQueueInstance - /datum/controller/process/bot/setup() name = "bot" schedule_interval = 20 // every 2 seconds - updateQueueInstance = new /datum/controller/process/bot/started() ..() - if(!updateQueueInstance) - if(!aibots) - aibots = list() - else if(aibots.len) - updateQueueInstance = new + if(!aibots) + aibots = list() + +/datum/controller/process/bot/statProcess() + ..() + stat(null, "[aibots && aibots.len] bots") /datum/controller/process/bot/doWork() - if(updateQueueInstance) - updateQueueInstance.init(aibots, "bot_process") - updateQueueInstance.Run() + for(last_object in aibots) + var/obj/machinery/bot/B = last_object + if(istype(B) && isnull(B.gcDestroyed)) + // Some bots sleep when they process, but there's not many bots, so just spawn them off + spawn(-1) + try + B.bot_process() + catch(var/exception/e) + catchException(e, B) + SCHECK + else + catchBadType(B) + aibots -= B diff --git a/code/controllers/Processes/disease.dm b/code/controllers/Processes/disease.dm deleted file mode 100644 index a8d840097ec..00000000000 --- a/code/controllers/Processes/disease.dm +++ /dev/null @@ -1,11 +0,0 @@ -/datum/controller/process/disease - var/tmp/datum/updateQueue/updateQueueInstance - -/datum/controller/process/disease/setup() - name = "disease" - schedule_interval = 20 // every 2 seconds - updateQueueInstance = new - -/datum/controller/process/disease/doWork() - updateQueueInstance.init(active_diseases, "process") - updateQueueInstance.Run() diff --git a/code/controllers/Processes/emergencyShuttle.dm b/code/controllers/Processes/emergencyShuttle.dm index e7289311b95..efd537bb062 100644 --- a/code/controllers/Processes/emergencyShuttle.dm +++ b/code/controllers/Processes/emergencyShuttle.dm @@ -1,5 +1,5 @@ /datum/controller/process/emergencyShuttle/setup() - name = "emergency shuttle" + name = "e-shuttle" schedule_interval = 20 // every 2 seconds if(!emergency_shuttle) diff --git a/code/controllers/Processes/garbage.dm b/code/controllers/Processes/garbage.dm index 9686bcd42b3..2e53be6414d 100644 --- a/code/controllers/Processes/garbage.dm +++ b/code/controllers/Processes/garbage.dm @@ -1,9 +1,15 @@ -/datum/controller/process/garbage/setup() +/datum/controller/process/garbage_collector/setup() name = "garbage" - schedule_interval = 20 // every 2 seconds + schedule_interval = 10 + start_delay = 3 - if(!garbageCollector) - garbageCollector = new + garbageCollector = src -/datum/controller/process/garbage/doWork() - garbageCollector.process() \ No newline at end of file +/datum/controller/process/garbage_collector/doWork() + // Garbage collection code can be found in code\modules\garbage collection\garbage_collector.dm + processGarbage() + +/datum/controller/process/garbage_collector/statProcess() + ..() + stat(null, "[del_everything ? "Off" : "On"], [queue.len] queued") + stat(null, "Dels: [dels_count], [soft_dels] soft, [hard_dels] hard") diff --git a/code/controllers/Processes/inactivity.dm b/code/controllers/Processes/inactivity.dm index e4cc04e4871..57e82348572 100644 --- a/code/controllers/Processes/inactivity.dm +++ b/code/controllers/Processes/inactivity.dm @@ -11,6 +11,6 @@ C << "You have been inactive for more than 10 minutes and have been disconnected." del(C) - scheck() + SCHECK #undef INACTIVITY_KICK*/ diff --git a/code/controllers/Processes/lighting.dm b/code/controllers/Processes/lighting.dm new file mode 100644 index 00000000000..7d463abbd7f --- /dev/null +++ b/code/controllers/Processes/lighting.dm @@ -0,0 +1,18 @@ +var/global/datum/controller/process/lighting/lighting_controller + +/datum/controller/process/lighting/setup() + name = "lighting" + schedule_interval = LIGHTING_INTERVAL + start_delay = 1 + lighting_controller = src + + create_lighting_overlays() + // Pre-process lighting once before the round starts. Wait 30 seconds so the away mission has time to load. + spawn(300) + doWork() + +/datum/controller/process/lighting/statProcess() + ..() + stat(null, "[last_light_count] lights, [last_overlay_count] overlays") + +// Lighting process code located in modules\lighting\lighting_process.dm \ No newline at end of file diff --git a/code/controllers/Processes/machinery.dm b/code/controllers/Processes/machinery.dm index 9d069101f54..8074578b323 100644 --- a/code/controllers/Processes/machinery.dm +++ b/code/controllers/Processes/machinery.dm @@ -3,6 +3,12 @@ /datum/controller/process/machinery/setup() name = "machinery" schedule_interval = 20 // every 2 seconds + start_delay = 12 + +/datum/controller/process/machinery/statProcess() + ..() + stat(null, "[machines.len] machines") + stat(null, "[powernets.len] powernets") /datum/controller/process/machinery/doWork() process_sort() @@ -13,22 +19,25 @@ /datum/controller/process/machinery/proc/process_sort() if(machinery_sort_required) machinery_sort_required = 0 - machines = dd_sortedObjectList(machines) + machines = dd_sortedObjectList(machines) /datum/controller/process/machinery/proc/process_machines() - for(var/obj/machinery/M in machines) - if(M && isnull(M.gcDestroyed)) + for(last_object in machines) + var/obj/machinery/M = last_object + if(istype(M) && isnull(M.gcDestroyed)) #ifdef PROFILE_MACHINES var/time_start = world.timeofday #endif - if(M.process() == PROCESS_KILL) - //M.inMachineList = 0 We don't use this debugging function - machines.Remove(M) - continue + try + if(M.process() == PROCESS_KILL) + machines.Remove(M) + continue - if(M && M.use_power) - M.auto_use_power() + if(M.use_power) + M.auto_use_power() + catch(var/exception/e) + catchException(e, M) #ifdef PROFILE_MACHINES var/time_end = world.timeofday @@ -39,15 +48,20 @@ machine_profiling[M.type] += (time_end - time_start) #endif else + catchBadType(M) machines -= M - scheck() + SCHECK_EVERY(100) /datum/controller/process/machinery/proc/process_power() - for(var/datum/powernet/powerNetwork in powernets) + for(last_object in powernets) + var/datum/powernet/powerNetwork = last_object if(istype(powerNetwork) && isnull(powerNetwork.gcDestroyed)) - powerNetwork.reset() - scheck() + try + powerNetwork.reset() + catch(var/exception/e) + catchException(e, powerNetwork) + SCHECK continue powernets.Remove(powerNetwork) @@ -57,4 +71,4 @@ for(var/obj/item/I in processing_power_items) if(!I.pwr_drain()) // 0 = Process Kill, remove from processing list. processing_power_items.Remove(I) - scheck() + SCHECK diff --git a/code/controllers/Processes/mob.dm b/code/controllers/Processes/mob.dm index 4be567c4ef2..be630a68fd8 100644 --- a/code/controllers/Processes/mob.dm +++ b/code/controllers/Processes/mob.dm @@ -1,27 +1,35 @@ /datum/controller/process/mob - var/tmp/datum/updateQueue/updateQueueInstance /datum/controller/process/mob/setup() name = "mob" schedule_interval = 20 // every 2 seconds - updateQueueInstance = new + start_delay = 16 if(!mob_master) mob_master = new mob_master.Setup() /datum/controller/process/mob/started() ..() - if(!updateQueueInstance) - if(!mob_list) - mob_list = list() - else if(mob_list.len) - updateQueueInstance = new + if(!mob_list) + mob_list = list() + +/datum/controller/process/mob/statProcess() + ..() + stat(null, "[mob_list.len] mobs") /datum/controller/process/mob/doWork() - if(updateQueueInstance) - updateQueueInstance.init(mob_list, "Life") - updateQueueInstance.Run() - mob_master.process() + for(last_object in mob_list) + var/mob/M = last_object + if(istype(M) && isnull(M.gcDestroyed)) + try + M.Life() + catch(var/exception/e) + catchException(e, M) + SCHECK + else + catchBadType(M) + mob_list -= M + mob_master.process() var/global/datum/controller/mob_system/mob_master diff --git a/code/controllers/Processes/nanoui.dm b/code/controllers/Processes/nanoui.dm index c8396bcab87..1667af943da 100644 --- a/code/controllers/Processes/nanoui.dm +++ b/code/controllers/Processes/nanoui.dm @@ -1,11 +1,19 @@ -/datum/controller/process/nanoui - var/tmp/datum/updateQueue/updateQueueInstance - /datum/controller/process/nanoui/setup() name = "nanoui" schedule_interval = 20 // every 2 seconds - updateQueueInstance = new + +/datum/controller/process/nanoui/statProcess() + ..() + stat(null, "[nanomanager.processing_uis.len] UIs") /datum/controller/process/nanoui/doWork() - updateQueueInstance.init(nanomanager.processing_uis, "process") - updateQueueInstance.Run() + for(last_object in nanomanager.processing_uis) + var/datum/nanoui/NUI = last_object + if(istype(NUI) && isnull(NUI.gcDestroyed)) + try + NUI.process() + catch(var/exception/e) + catchException(e, NUI) + else + catchBadType(NUI) + nanomanager.processing_uis -= NUI diff --git a/code/controllers/Processes/obj.dm b/code/controllers/Processes/obj.dm index 15ad98dd3d6..0e573bcc05c 100644 --- a/code/controllers/Processes/obj.dm +++ b/code/controllers/Processes/obj.dm @@ -1,21 +1,28 @@ -var/global/list/object_profiling = list() -/datum/controller/process/obj - var/tmp/datum/updateQueue/updateQueueInstance - /datum/controller/process/obj/setup() name = "obj" schedule_interval = 20 // every 2 seconds - updateQueueInstance = new + start_delay = 8 /datum/controller/process/obj/started() ..() - if(!updateQueueInstance) - if(!processing_objects) - processing_objects = list() - else if(processing_objects.len) - updateQueueInstance = new + if(!processing_objects) + processing_objects = list() + +/datum/controller/process/obj/statProcess() + ..() + stat(null, "[processing_objects.len] objects") /datum/controller/process/obj/doWork() - if(updateQueueInstance) - updateQueueInstance.init(processing_objects, "process") - updateQueueInstance.Run() + for(last_object in processing_objects) + var/datum/O = last_object + if(istype(O) && isnull(O.gcDestroyed)) + try + // Reagent datums get shoved in here, but the process proc isn't on the + // base datum type, so we just call it blindly. + O:process() + catch(var/exception/e) + catchException(e, O) + SCHECK + else + catchBadType(O) + processing_objects -= O diff --git a/code/controllers/Processes/pipenet.dm b/code/controllers/Processes/pipenet.dm index b59373a88a1..f7b01391543 100644 --- a/code/controllers/Processes/pipenet.dm +++ b/code/controllers/Processes/pipenet.dm @@ -1,12 +1,22 @@ /datum/controller/process/pipenet/setup() name = "pipenet" schedule_interval = 20 // every 2 seconds + start_delay = 18 + +/datum/controller/process/pipenet/statProcess() + ..() + stat(null, "[pipe_networks.len] pipe nets") /datum/controller/process/pipenet/doWork() - for(var/datum/pipe_network/pipeNetwork in pipe_networks) + for(last_object in pipe_networks) + var/datum/pipe_network/pipeNetwork = last_object if(istype(pipeNetwork) && isnull(pipeNetwork.gcDestroyed)) - pipeNetwork.process() - scheck() + try + pipeNetwork.process() + catch(var/exception/e) + catchException(e, pipeNetwork) + SCHECK continue else + catchBadType(pipeNetwork) pipe_networks -= pipeNetwork diff --git a/code/controllers/Processes/shuttle.dm b/code/controllers/Processes/shuttle.dm index a10586d76d9..df0e5fa1ae2 100644 --- a/code/controllers/Processes/shuttle.dm +++ b/code/controllers/Processes/shuttle.dm @@ -1,5 +1,5 @@ /datum/controller/process/Shuttle/setup() - name = "shuttle controller" + name = "shuttle" schedule_interval = 20 // every 2 seconds if(!shuttle_controller) diff --git a/code/controllers/Processes/sun.dm b/code/controllers/Processes/sun.dm index 93e626af3bb..abd2dc5433d 100644 --- a/code/controllers/Processes/sun.dm +++ b/code/controllers/Processes/sun.dm @@ -44,8 +44,17 @@ var/global/datum/controller/process/sun/sun //now tell the solar control computers to update their status and linked devices /datum/controller/process/sun/proc/update_solar_machinery() - for(var/obj/machinery/power/solar_control/SC in solars) - if(!SC.powernet) - solars.Remove(SC) - continue - SC.update() + for(last_object in solars) + var/obj/machinery/power/solar_control/SC = last_object + if(istype(SC) && isnull(SC.gcDestroyed)) + if(!SC.powernet) + solars -= SC + continue + try + SC.update() + catch(var/exception/e) + catchException(e, SC) + SCHECK + else + catchBadType(SC) + solars -= SC diff --git a/code/controllers/Processes/supply.dm b/code/controllers/Processes/supply.dm index 891a511ec6d..aa4ba1e52ab 100644 --- a/code/controllers/Processes/supply.dm +++ b/code/controllers/Processes/supply.dm @@ -1,5 +1,5 @@ /datum/controller/process/supply/setup() - name = "supply controller" + name = "supply" schedule_interval = 300 // every 30 seconds /datum/controller/process/supply/doWork() diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm index 137eeb3aff1..3ecef1fa27a 100644 --- a/code/controllers/master_controller.dm +++ b/code/controllers/master_controller.dm @@ -20,8 +20,6 @@ var/global/pipe_processing_killed = 0 datum/controller/game_controller var/list/shuttle_list // For debugging and VV - var/global/datum/garbage_collector/garbageCollector - datum/controller/game_controller/New() //There can be only one master_controller. Out with the old and in with the new. if(master_controller != src) diff --git a/code/controllers/subsystem/alarms.dm b/code/controllers/subsystem/alarms.dm deleted file mode 100644 index 1e33fc7246b..00000000000 --- a/code/controllers/subsystem/alarms.dm +++ /dev/null @@ -1,30 +0,0 @@ -// We manually initialize the alarm handlers instead of looping over all existing types -// to make it possible to write: camera.triggerAlarm() rather than alarm_manager.managers[datum/alarm_handler/camera].triggerAlarm() or a variant thereof. -/var/global/datum/alarm_handler/atmosphere/atmosphere_alarm = new() -/var/global/datum/alarm_handler/camera/camera_alarm = new() -/var/global/datum/alarm_handler/fire/fire_alarm = new() -/var/global/datum/alarm_handler/motion/motion_alarm = new() -/var/global/datum/alarm_handler/power/power_alarm = new() - -/datum/subsystem/alarm - name = "Alarm" - var/list/datum/alarm/all_handlers - -/datum/subsystem/alarm/New() - all_handlers = list(atmosphere_alarm, camera_alarm, fire_alarm, motion_alarm, power_alarm) - -/datum/subsystem/alarm/fire() - for(var/datum/alarm_handler/AH in all_handlers) - AH.process() - -/datum/subsystem/alarm/proc/active_alarms() - var/list/all_alarms = new - for(var/datum/alarm_handler/AH in all_handlers) - var/list/alarms = AH.alarms - all_alarms += alarms - - return all_alarms - -/datum/subsystem/alarm/proc/number_of_active_alarms() - var/list/alarms = active_alarms() - return alarms.len diff --git a/code/controllers/subsystems.dm b/code/controllers/subsystems.dm deleted file mode 100644 index 11025d8d535..00000000000 --- a/code/controllers/subsystems.dm +++ /dev/null @@ -1,46 +0,0 @@ -#define NEW_SS_GLOBAL(varname) if(varname != src){if(istype(varname)){Recover();qdel(varname);}varname = src;} - -/datum/subsystem - //things you will want to define - var/name //name of the subsystem - var/priority = 0 //priority affects order of initialization. Higher priorities are initialized first, lower priorities later. Can be decimal and negative values. - var/wait = 20 //time to wait (in deciseconds) between each call to fire(). Must be a positive integer. - - //things you will probably want to leave alone - var/can_fire = 0 //prevent fire() calls - var/last_fire = 0 //last world.time we called fire() - var/next_fire = 0 //scheduled world.time for next fire() - var/cpu = 0 //cpu-usage stats (somewhat vague) - var/cost = 0 //average time to execute - var/times_fired = 0 //number of times we have called fire() - -//used to initialize the subsystem BEFORE the map has loaded -/datum/subsystem/New() - -//previously, this would have been named 'process()' but that name is used everywhere for different things! -//fire() seems more suitable. This is the procedure that gets called every 'wait' deciseconds. -//fire(), and the procs it calls, SHOULD NOT HAVE ANY SLEEP OPERATIONS in them! -//YE BE WARNED! -/datum/subsystem/proc/fire() - can_fire = 0 - -//used to initialize the subsystem AFTER the map has loaded -/datum/subsystem/proc/Initialize(start_timeofday) - var/time = (world.timeofday - start_timeofday) / 10 - var/msg = "Initialized [name] SubSystem within [time] seconds" - world << "[msg]" - world.log << msg - -//hook for printing stats to the "MC" statuspanel for admins to see performance and related stats etc. -/datum/subsystem/proc/stat_entry() - stat(name, "[round(cost,0.001)]ds\t(CPU:[round(cpu,1)]%)") - -//could be used to postpone a costly subsystem for one cycle -//for instance, during cpu intensive operations like explosions -/datum/subsystem/proc/postpone() - if(next_fire - world.time < wait) - next_fire += wait - -//usually called via datum/subsystem/New() when replacing a subsystem (i.e. due to a recurring crash) -//should attempt to salvage what it can from the old instance of subsystem -/datum/subsystem/proc/Recover() diff --git a/code/modules/garbage collection/garbage_collector.dm b/code/modules/garbage collection/garbage_collector.dm index 97d67c30ac8..41c01dc5672 100644 --- a/code/modules/garbage collection/garbage_collector.dm +++ b/code/modules/garbage collection/garbage_collector.dm @@ -2,21 +2,21 @@ // For general information about how the GC works and how to use it, see __gc_info.dm -#define GC_COLLECTIONS_PER_TICK 300 // Was 100. +#define GC_COLLECTIONS_PER_TICK 150 // Was 100. #define GC_COLLECTION_TIMEOUT (30 SECONDS) -#define GC_FORCE_DEL_PER_TICK 60 +#define GC_FORCE_DEL_PER_TICK 30 //#define GC_DEBUG // A list of types that were queued in the GC, and had to be soft deleted; used in testing var/list/gc_hard_del_types = list() -var/datum/garbage_collector/garbageCollector +var/global/datum/controller/process/garbage_collector/garbageCollector // The time a datum was destroyed by the GC, or null if it hasn't been /datum/var/gcDestroyed // Whether a datum was hard-deleted by the GC; 0 if not, 1 if it was queued, -1 if directly deleted /datum/var/hard_deleted = 0 -/datum/garbage_collector +/datum/controller/process/garbage_collector var/list/queue = new var/del_everything = 0 @@ -25,7 +25,7 @@ var/datum/garbage_collector/garbageCollector var/hard_dels = 0 var/soft_dels = 0 -/datum/garbage_collector/proc/addTrash(var/datum/D) +/datum/controller/process/garbage_collector/proc/addTrash(var/datum/D) if(!istype(D) || del_everything) del(D) hard_dels++ @@ -35,7 +35,7 @@ var/datum/garbage_collector/garbageCollector queue -= "\ref[D]" // If this is a re-used ref, remove the old ref from the queue queue["\ref[D]"] = world.time -/datum/garbage_collector/proc/process() +/datum/controller/process/garbage_collector/proc/processGarbage() var/remainingCollectionPerTick = GC_COLLECTIONS_PER_TICK var/remainingForceDelPerTick = GC_FORCE_DEL_PER_TICK var/collectionTimeScope = world.time - GC_COLLECTION_TIMEOUT @@ -60,10 +60,13 @@ var/datum/garbage_collector/garbageCollector queue.Cut(1, 2) remainingForceDelPerTick-- + // Sleep check more aggressively when force deleting. + calls_since_last_scheck += 9 else // Otherwise, it was GC'd - remove it from the queue queue.Cut(1, 2) soft_dels++ dels_count++ + SCHECK #ifdef GC_DEBUG #undef GC_DEBUG @@ -73,7 +76,7 @@ var/datum/garbage_collector/garbageCollector #undef GC_COLLECTION_TIMEOUT #undef GC_COLLECTIONS_PER_TICK -/datum/garbage_collector/proc/hardDel(var/datum/D) +/datum/controller/process/garbage_collector/proc/hardDel(var/datum/D) gc_hard_del_types |= D.type D.hard_deleted = 1 if(!D.gcDestroyed) diff --git a/code/modules/lighting/lighting_process.dm b/code/modules/lighting/lighting_process.dm index ef13726cdef..916920393ba 100644 --- a/code/modules/lighting/lighting_process.dm +++ b/code/modules/lighting/lighting_process.dm @@ -1,14 +1,10 @@ -var/global/datum/controller/process/lighting/lighting_controller - -/datum/controller/process/lighting/setup() - name = "lighting" - lighting_controller = src - schedule_interval = LIGHTING_INTERVAL - - create_lighting_overlays() +/datum/controller/process/lighting + var/last_light_count = 0 + var/last_overlay_count = 0 /datum/controller/process/lighting/doWork() - var/list/lighting_update_lights_old = lighting_update_lights //We use a different list so any additions to the update lists during a delay from scheck() don't cause things to be cut from the list without being updated. + var/list/lighting_update_lights_old = lighting_update_lights //We use a different list so any additions to the update lists during a delay from SCHECK don't cause things to be cut from the list without being updated. + last_light_count = lighting_update_lights.len lighting_update_lights = null //Nulling it first because of http://www.byond.com/forum/?post=1854520 lighting_update_lights = list() @@ -25,9 +21,10 @@ var/global/datum/controller/process/lighting/lighting_controller L.force_update = 0 L.needs_update = 0 - scheck() + SCHECK var/list/lighting_update_overlays_old = lighting_update_overlays //Same as above. + last_overlay_count = lighting_update_overlays.len lighting_update_overlays = null //Same as above lighting_update_overlays = list() @@ -35,4 +32,4 @@ var/global/datum/controller/process/lighting/lighting_controller O.update_overlay() O.needs_update = 0 - scheck() + SCHECK diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 43cb845414d..2b94fdae71c 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -926,77 +926,12 @@ var/list/slot_equipment_priority = list( \ if(client && client.holder) if(statpanel("DI")) //not looking at that panel - stat(null, "Location:\t([x], [y], [z])") - stat(null, "CPU:\t[world.cpu]") - stat(null, "Instances:\t[world.contents.len]") + stat("Loc", "([x], [y], [z]) [loc]") + stat("CPU", "[world.cpu]") + stat("Instances", "[world.contents.len]") - if (garbageCollector) - stat(null, "\tqdel - [garbageCollector.del_everything ? "off" : "on"]") - stat(null, "\ton queue - [garbageCollector.queue.len]") - stat(null, "\ttotal delete - [garbageCollector.dels_count]") - stat(null, "\tsoft delete - [garbageCollector.soft_dels]") - stat(null, "\thard delete - [garbageCollector.hard_dels]") - else - stat(null, "Garbage Controller is not running.") - - if(processScheduler.getIsRunning()) - var/datum/controller/process/process - - process = processScheduler.getProcess("ticker") - stat(null, "TIC\t - #[process.getTicks()]\t - [process.getLastRunTime()]") - - process = processScheduler.getProcess("air") - stat(null, "AIR\t - #[process.getTicks()]\t - [process.getLastRunTime()]") - - process = processScheduler.getProcess("lighting") - stat(null, "LIG\t - #[process.getTicks()]\t - [process.getLastRunTime()]") - - process = processScheduler.getProcess("mob") - stat(null, "MOB([mob_list.len])\t - #[process.getTicks()]\t - [process.getLastRunTime()]") - - process = processScheduler.getProcess("machinery") - stat(null, "MAC([machines.len])\t - #[process.getTicks()]\t - [process.getLastRunTime()]") - - process = processScheduler.getProcess("obj") - stat(null, "OBJ([processing_objects.len])\t - #[process.getTicks()]\t - [process.getLastRunTime()]") - - process = processScheduler.getProcess("bot") - stat(null, "BOT([aibots.len])\t - #[process.getTicks()]\t - [process.getLastRunTime()]") - - process = processScheduler.getProcess("pipenet") - stat(null, "PIP([pipe_networks.len])\t - #[process.getTicks()]\t - [process.getLastRunTime()]") - - process = processScheduler.getProcess("nanoui") - stat(null, "NAN([nanomanager.processing_uis.len])\t - #[process.getTicks()]\t - [process.getLastRunTime()]") - - process = processScheduler.getProcess("disease") - stat(null, "DIS([active_diseases.len])\t - #[process.getTicks()]\t - [process.getLastRunTime()]") - - process = processScheduler.getProcess("garbage") - stat(null, "GAR\t - #[process.getTicks()]\t - [process.getLastRunTime()]") - - process = processScheduler.getProcess("sun") - stat(null, "SUN([sun.solars.len])\t - #[process.getTicks()]\t - [process.getLastRunTime()]") - - //process = processScheduler.getProcess("garbage") - //stat(null, "GAR\t - #[process.getTicks()]\t - [process.getLastRunTime()]") - - //process = processScheduler.getProcess("vote") - //stat(null, "VOT\t - #[process.getTicks()]\t - [process.getLastRunTime()]") - - //process = processScheduler.getProcess("shuttle controller") - //stat(null, "SHT\t - #[process.getTicks()]\t - [process.getLastRunTime()]") - - //process = processScheduler.getProcess("emergency shuttle") - //stat(null, "EME\t - #[process.getTicks()]\t - [process.getLastRunTime()]") - - //process = processScheduler.getProcess("inactivity") - //stat(null, "IAC\t - #[process.getTicks()]\t - [process.getLastRunTime()]") - - //process = processScheduler.getProcess("event") - //stat(null, "EVE([events.len])\t - #[process.getTicks()]\t - [process.getLastRunTime()]") - else - stat(null, "processScheduler is not running.") + if(processScheduler) + processScheduler.statProcesses() statpanel("Status") // Switch to the Status panel again, for the sake of the lazy Stat procs diff --git a/config/news/trivial.txt b/config/news/trivial.txt index f27ecfb791f..82b5a53c92b 100644 --- a/config/news/trivial.txt +++ b/config/news/trivial.txt @@ -1,4 +1,4 @@ -Tree stuck in tajaran; firefighters baffled. +Tree stuck in tajaran; firefighters baffled. Armadillos want aardvarks removed from dictionary claims 'here first'. Angel found dancing on pinhead ordered to stop; cited for public nuisance. Letters claim they are better than numbers; 'Always have been'. diff --git a/paradise.dme b/paradise.dme index 7d3cd4d7a8b..f90a049128f 100644 --- a/paradise.dme +++ b/paradise.dme @@ -18,6 +18,7 @@ #include "code\__DEFINES\_readme.dm" #include "code\__DEFINES\admin.dm" #include "code\__DEFINES\atmospherics.dm" +#include "code\__DEFINES\btime.dm" #include "code\__DEFINES\clothing.dm" #include "code\__DEFINES\combat.dm" #include "code\__DEFINES\flags.dm" @@ -31,6 +32,7 @@ #include "code\__DEFINES\misc.dm" #include "code\__DEFINES\mob.dm" #include "code\__DEFINES\preferences.dm" +#include "code\__DEFINES\process_scheduler.dm" #include "code\__DEFINES\qdel.dm" #include "code\__DEFINES\sight.dm" #include "code\__DEFINES\stat.dm" @@ -145,17 +147,16 @@ #include "code\controllers\hooks.dm" #include "code\controllers\master_controller.dm" #include "code\controllers\shuttle_controller.dm" -#include "code\controllers\subsystems.dm" #include "code\controllers\verbs.dm" #include "code\controllers\voting.dm" #include "code\controllers\Processes\air.dm" #include "code\controllers\Processes\alarm.dm" #include "code\controllers\Processes\bot.dm" -#include "code\controllers\Processes\disease.dm" #include "code\controllers\Processes\emergencyShuttle.dm" #include "code\controllers\Processes\event.dm" #include "code\controllers\Processes\garbage.dm" #include "code\controllers\Processes\inactivity.dm" +#include "code\controllers\Processes\lighting.dm" #include "code\controllers\Processes\machinery.dm" #include "code\controllers\Processes\mob.dm" #include "code\controllers\Processes\nanoui.dm" @@ -166,13 +167,9 @@ #include "code\controllers\Processes\supply.dm" #include "code\controllers\Processes\ticker.dm" #include "code\controllers\Processes\vote.dm" -#include "code\controllers\ProcessScheduler\core\_define.dm" #include "code\controllers\ProcessScheduler\core\_stubs.dm" #include "code\controllers\ProcessScheduler\core\process.dm" #include "code\controllers\ProcessScheduler\core\processScheduler.dm" -#include "code\controllers\ProcessScheduler\core\updateQueue.dm" -#include "code\controllers\ProcessScheduler\core\updateQueueWorker.dm" -#include "code\controllers\subsystem\alarms.dm" #include "code\datums\ai_laws.dm" #include "code\datums\browser.dm" #include "code\datums\cargoprofile.dm"