Files
Bubberstation/code/controllers/subsystem/circuit_component.dm
SkyratBot 25fb2e098b [MIRROR] Adds error on qdeling callback, fixes errors this causes [MDB IGNORE] (#23271)
* Adds error on qdeling callback, fixes errors this causes (#77850)

## About The Pull Request

You shouldn't ever qdel a callback. If you don't want to own it free
your ref (remove it from a list/set it to null). When all refs are
cleared it'll get cleaned up by byond itself

* Adds error on qdeling callback, fixes errors this causes

* Update cell_component.dm

* Update acid.dm

---------

Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com>
2023-08-23 04:43:34 -04:00

87 lines
2.7 KiB
Plaintext

SUBSYSTEM_DEF(circuit_component)
name = "Circuit Components"
wait = 0.1 SECONDS
priority = FIRE_PRIORITY_DEFAULT
flags = SS_NO_INIT
var/list/callbacks_to_invoke = list()
var/list/currentrun = list()
var/list/instant_run_stack = list()
var/instant_run_tick = 0
var/instant_run_start_cpu_usage = 0
var/instant_run_max_cpu_usage = 10
var/list/instant_run_callbacks_to_run = list()
/datum/controller/subsystem/circuit_component/fire(resumed)
if(!resumed)
currentrun = callbacks_to_invoke.Copy()
callbacks_to_invoke.Cut()
while(length(currentrun))
var/datum/callback/to_call = currentrun[1]
currentrun.Cut(1,2)
if(QDELETED(to_call))
continue
to_call.user = null
to_call.InvokeAsync()
if(MC_TICK_CHECK)
return
/**
* Adds a callback to be invoked when the next fire() is done. Used by the integrated circuit system.
*
* Prevents race conditions as it acts like a queue system.
* Those that registered first will be executed first and those registered last will be executed last.
*/
/datum/controller/subsystem/circuit_component/proc/add_callback(datum/port/input, datum/callback/to_call)
if(instant_run_tick == world.time && (TICK_USAGE - instant_run_start_cpu_usage) < instant_run_max_cpu_usage)
instant_run_callbacks_to_run += to_call
return
callbacks_to_invoke += to_call
/// Queues any callbacks to be executed instantly instead of using the subsystem.
/datum/controller/subsystem/circuit_component/proc/queue_instant_run(start_cpu_time)
if(instant_run_tick)
instant_run_stack += list(instant_run_callbacks_to_run)
// If we're already instantly executing, don't change the start_cpu_time.
start_cpu_time = instant_run_start_cpu_usage
if(!start_cpu_time)
start_cpu_time = TICK_USAGE
instant_run_tick = world.time
instant_run_start_cpu_usage = start_cpu_time
instant_run_callbacks_to_run = list()
/**
* Instantly executes the stored callbacks and does this in a loop until there are no stored callbacks or it hits tick limit.
*
* Returns a list containing any values added by any input port.
*/
/datum/controller/subsystem/circuit_component/proc/execute_instant_run()
var/list/received_inputs = list()
while(length(instant_run_callbacks_to_run))
var/list/instant_run_currentrun = instant_run_callbacks_to_run
instant_run_callbacks_to_run = list()
while(length(instant_run_currentrun))
var/datum/callback/to_call = instant_run_currentrun[1]
instant_run_currentrun.Cut(1,2)
to_call.user = null
to_call.InvokeAsync(received_inputs)
if(length(instant_run_stack))
instant_run_callbacks_to_run = pop(instant_run_stack)
else
instant_run_tick = 0
if((TICK_USAGE - instant_run_start_cpu_usage) < instant_run_max_cpu_usage)
return received_inputs
else
return null