mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-22 20:43:10 +01:00
Updated SSgarbage (#18173)
* pain * sadfas * sdfa * sdfasf * sfa * sdf * might the lord have mercy on our soul * i cri everidai * adeste fideles * sdf * where will this lead, what's coming next, from your inventions * dear lord * gjvhk * i cri everidai * fsgf * sdfa * sdaf * hiuhi
This commit is contained in:
+50
-24
@@ -1,15 +1,14 @@
|
||||
/datum
|
||||
var/tmp/list/active_timers
|
||||
var/tmp/datum/weakref/weakref
|
||||
var/tmp/isprocessing = 0
|
||||
|
||||
/**
|
||||
* Tick count time when this object was destroyed.
|
||||
*
|
||||
* If this is non zero then the object has been garbage collected and is awaiting either
|
||||
* a hard del by the GC subsystme, or to be autocollected (if it has no references)
|
||||
*/
|
||||
var/tmp/gcDestroyed
|
||||
var/gc_destroyed
|
||||
|
||||
var/tmp/list/active_timers
|
||||
var/tmp/isprocessing = 0
|
||||
|
||||
/// Status traits attached to this datum. associative list of the form: list(trait name (string) = list(source1, source2, source3,...))
|
||||
var/list/status_traits
|
||||
@@ -24,10 +23,9 @@
|
||||
/// Is this datum capable of sending signals?
|
||||
/// Set to true when a signal has been registered
|
||||
var/signal_enabled = FALSE
|
||||
/// A cached version of our \ref
|
||||
/// The brunt of \ref costs are in creating entries in the string tree (a tree of immutable strings)
|
||||
/// This avoids doing that more then once per datum by ensuring ref strings always have a reference to them after they're first pulled
|
||||
var/cached_ref
|
||||
|
||||
/// A weak reference to another datum
|
||||
var/datum/weakref/weak_reference
|
||||
|
||||
#ifdef REFERENCE_TRACKING
|
||||
var/running_find_references
|
||||
@@ -38,29 +36,29 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// If we have called dump_harddel_info already. Used to avoid duped calls (since we call it immediately in some cases on failure to process)
|
||||
// Create and destroy is weird and I wanna cover my bases
|
||||
var/harddel_deets_dumped = FALSE
|
||||
|
||||
// Default implementation of clean-up code.
|
||||
// This should be overridden to remove all references pointing to the object being destroyed.
|
||||
// Return the appropriate QDEL_HINT; in most cases this is QDEL_HINT_QUEUE.
|
||||
/datum/proc/Destroy(force=FALSE)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
//SHOULD_NOT_SLEEP(TRUE) //Soon my friend, soon...
|
||||
|
||||
weakref = null
|
||||
GLOB.destroyed_event.raise_event(src)
|
||||
var/ui_key = SOFTREF(src)
|
||||
if(LAZYISIN(SSnanoui.open_uis, ui_key))
|
||||
SSnanoui.close_uis(src)
|
||||
tag = null
|
||||
var/list/timers = active_timers
|
||||
active_timers = null
|
||||
if (timers)
|
||||
for (var/thing in timers)
|
||||
var/datum/timedevent/timer = thing
|
||||
if (timer.spent)
|
||||
continue
|
||||
qdel(timer)
|
||||
weak_reference = null //ensure prompt GCing of weakref.
|
||||
|
||||
// Handle components & signals
|
||||
signal_enabled = FALSE
|
||||
if(active_timers)
|
||||
var/list/timers = active_timers
|
||||
active_timers = null
|
||||
if (timers)
|
||||
for (var/thing in timers)
|
||||
var/datum/timedevent/timer = thing
|
||||
if (timer.spent)
|
||||
continue
|
||||
qdel(timer)
|
||||
|
||||
#ifdef REFERENCE_TRACKING
|
||||
#ifdef REFERENCE_TRACKING_DEBUG
|
||||
@@ -68,6 +66,19 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
GLOB.destroyed_event.raise_event(src)
|
||||
if (!isturf(src))
|
||||
cleanup_events(src)
|
||||
|
||||
var/ui_key = SOFTREF(src)
|
||||
if(LAZYISIN(SSnanoui.open_uis, ui_key))
|
||||
SSnanoui.close_uis(src)
|
||||
|
||||
|
||||
// Handle components & signals
|
||||
signal_enabled = FALSE
|
||||
|
||||
//BEGIN: ECS SHIT
|
||||
var/list/dc = datum_components
|
||||
if(dc)
|
||||
var/all_components = dc[/datum/component]
|
||||
@@ -95,6 +106,7 @@
|
||||
|
||||
for(var/target in signal_procs)
|
||||
UnregisterSignal(target, signal_procs[target])
|
||||
//END: ECS SHIT
|
||||
|
||||
return QDEL_HINT_QUEUE
|
||||
|
||||
@@ -125,3 +137,17 @@
|
||||
return FALSE
|
||||
vars[var_name] = var_value
|
||||
return TRUE
|
||||
|
||||
|
||||
/// Return text from this proc to provide extra context to hard deletes that happen to it
|
||||
/// Optional, you should use this for cases where replication is difficult and extra context is required
|
||||
/// Can be called more then once per object, use harddel_deets_dumped to avoid duplicate calls (I am so sorry)
|
||||
/datum/proc/dump_harddel_info()
|
||||
return
|
||||
|
||||
///images are pretty generic, this should help a bit with tracking harddels related to them
|
||||
/image/dump_harddel_info()
|
||||
if(harddel_deets_dumped)
|
||||
return
|
||||
harddel_deets_dumped = TRUE
|
||||
return "Image icon: [icon] - icon_state: [icon_state] [loc ? "loc: [loc] ([loc.x],[loc.y],[loc.z])" : ""]"
|
||||
|
||||
@@ -2,17 +2,22 @@
|
||||
var/list/steps
|
||||
var/atom/holder
|
||||
var/result
|
||||
var/list/steps_desc
|
||||
var/current_desc = null
|
||||
|
||||
/datum/construction/New(atom)
|
||||
..()
|
||||
holder = atom
|
||||
if(!holder) //don't want this without a holder
|
||||
spawn
|
||||
qdel(src)
|
||||
qdel(src)
|
||||
set_desc(steps.len)
|
||||
|
||||
/datum/construction/Destroy(force)
|
||||
holder = null
|
||||
|
||||
steps = null
|
||||
|
||||
. = ..()
|
||||
|
||||
/datum/construction/proc/next_step()
|
||||
steps.len--
|
||||
if(!steps.len)
|
||||
@@ -60,8 +65,7 @@
|
||||
/datum/construction/proc/spawn_result()
|
||||
if(result)
|
||||
new result(get_turf(holder))
|
||||
spawn()
|
||||
qdel(holder)
|
||||
QDEL_NULL(holder)
|
||||
|
||||
/datum/construction/proc/set_desc(index as num)
|
||||
var/list/step = steps[index]
|
||||
|
||||
@@ -1,4 +1 @@
|
||||
/****************
|
||||
* Debug Support *
|
||||
****************/
|
||||
GLOBAL_LIST_EMPTY(all_observable_events)
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
GLOBAL_LIST_EMPTY(global_listen_count)
|
||||
GLOBAL_LIST_EMPTY(event_sources_count)
|
||||
GLOBAL_LIST_EMPTY(event_listen_count)
|
||||
|
||||
/proc/cleanup_events(source)
|
||||
if(GLOB.global_listen_count && GLOB.global_listen_count[source])
|
||||
cleanup_global_listener(source, GLOB.global_listen_count[source])
|
||||
if(GLOB.event_sources_count && GLOB.event_sources_count[source])
|
||||
cleanup_source_listeners(source, GLOB.event_sources_count[source])
|
||||
if(GLOB.event_listen_count && GLOB.event_listen_count[source])
|
||||
cleanup_event_listener(source, GLOB.event_listen_count[source])
|
||||
|
||||
/singleton/observ/register(datum/event_source, datum/listener, proc_call)
|
||||
. = ..()
|
||||
if(.)
|
||||
GLOB.event_sources_count[event_source] += 1
|
||||
GLOB.event_listen_count[listener] += 1
|
||||
|
||||
/singleton/observ/unregister(datum/event_source, datum/listener, proc_call)
|
||||
. = ..()
|
||||
if(.)
|
||||
GLOB.event_sources_count[event_source] -= 1
|
||||
GLOB.event_listen_count[listener] -= 1
|
||||
|
||||
if(GLOB.event_sources_count[event_source] <= 0)
|
||||
GLOB.event_sources_count -= event_source
|
||||
if(GLOB.event_listen_count[listener] <= 0)
|
||||
GLOB.event_listen_count -= listener
|
||||
|
||||
/singleton/observ/register_global(datum/listener, proc_call)
|
||||
. = ..()
|
||||
if(.)
|
||||
GLOB.global_listen_count[listener] += 1
|
||||
|
||||
/singleton/observ/unregister_global(datum/listener, proc_call)
|
||||
. = ..()
|
||||
if(.)
|
||||
GLOB.global_listen_count[listener] -= 1
|
||||
if(GLOB.global_listen_count[listener] <= 0)
|
||||
GLOB.global_listen_count -= listener
|
||||
|
||||
/proc/cleanup_global_listener(listener, listen_count)
|
||||
GLOB.global_listen_count -= listener
|
||||
for(var/entry in GLOB.all_observable_events)
|
||||
var/singleton/observ/event = entry
|
||||
if(event.unregister_global(listener))
|
||||
log_debug("[event] - [listener] was deleted while still registered to global events.")
|
||||
if(!(--listen_count))
|
||||
return
|
||||
|
||||
/proc/cleanup_source_listeners(event_source, source_listener_count)
|
||||
GLOB.event_sources_count -= event_source
|
||||
for(var/entry in GLOB.all_observable_events)
|
||||
var/singleton/observ/event = entry
|
||||
var/proc_owners = event.event_sources[event_source]
|
||||
if(proc_owners)
|
||||
for(var/proc_owner in proc_owners)
|
||||
if(event.unregister(event_source, proc_owner))
|
||||
log_debug("[event] - [event_source] was deleted while still being listened to by [proc_owner].")
|
||||
if(!(--source_listener_count))
|
||||
return
|
||||
|
||||
/proc/cleanup_event_listener(listener, listener_count)
|
||||
GLOB.event_listen_count -= listener
|
||||
for(var/entry in GLOB.all_observable_events)
|
||||
var/singleton/observ/event = entry
|
||||
for(var/event_source in event.event_sources)
|
||||
if(event.unregister(event_source, listener))
|
||||
log_debug("[event] - [listener] was deleted while still listening to [event_source].")
|
||||
if(!(--listener_count))
|
||||
return
|
||||
@@ -1,17 +0,0 @@
|
||||
/datum/weakref
|
||||
var/ref
|
||||
|
||||
/datum/weakref/New(datum/D)
|
||||
ref = SOFTREF(D)
|
||||
|
||||
/datum/weakref/Destroy(force = 0)
|
||||
crash_with("Some fuck is trying to [force ? "force-" : ""]delete a weakref!")
|
||||
if (!force)
|
||||
return QDEL_HINT_LETMELIVE // feck off
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/weakref/proc/resolve()
|
||||
var/datum/D = locate(ref)
|
||||
if (!QDELETED(D) && D.weakref == src)
|
||||
. = D
|
||||
@@ -0,0 +1,95 @@
|
||||
/// Creates a weakref to the given input.
|
||||
/// See /datum/weakref's documentation for more information.
|
||||
/proc/WEAKREF(datum/input)
|
||||
if(istype(input) && !QDELETED(input))
|
||||
if(isweakref(input))
|
||||
return input
|
||||
|
||||
if(!input.weak_reference)
|
||||
input.weak_reference = new /datum/weakref(input)
|
||||
return input.weak_reference
|
||||
|
||||
/datum/proc/create_weakref() //Forced creation for admin proccalls
|
||||
return WEAKREF(src)
|
||||
|
||||
/**
|
||||
* A weakref holds a non-owning reference to a datum.
|
||||
* The datum can be referenced again using `resolve()`.
|
||||
*
|
||||
* To figure out why this is important, you must understand how deletion in
|
||||
* BYOND works.
|
||||
*
|
||||
* Imagine a datum as a TV in a living room. When one person enters to watch
|
||||
* TV, they turn it on. Others can come into the room and watch the TV.
|
||||
* When the last person leaves the room, they turn off the TV because it's
|
||||
* no longer being used.
|
||||
*
|
||||
* A datum being deleted tells everyone who's watching the TV to stop.
|
||||
* If everyone leaves properly (AKA cleaning up their references), then the
|
||||
* last person will turn off the TV, and everything is well.
|
||||
* However, if someone is resistant (holds a hard reference after deletion),
|
||||
* then someone has to walk in, drag them away, and turn off the TV forecefully.
|
||||
* This process is very slow, and it's known as hard deletion.
|
||||
*
|
||||
* This is where weak references come in. Weak references don't count as someone
|
||||
* watching the TV. Thus, when what it's referencing is destroyed, it will
|
||||
* hopefully clean up properly, and limit hard deletions.
|
||||
*
|
||||
* A common use case for weak references is holding onto what created itself.
|
||||
* For example, if a machine wanted to know what its last user was, it might
|
||||
* create a `var/mob/living/last_user`. However, this is a strong reference to
|
||||
* the mob, and thus will force a hard deletion when that mob is deleted.
|
||||
* It is often better in this case to instead create a weakref to the user,
|
||||
* meaning this type definition becomes `var/datum/weakref/last_user`.
|
||||
*
|
||||
* A good rule of thumb is that you should hold strong references to things
|
||||
* that you *own*. For example, a dog holding a chew toy would be the owner
|
||||
* of that chew toy, and thus a `var/obj/item/chew_toy` reference is fine
|
||||
* (as long as it is cleaned up properly).
|
||||
* However, a chew toy does not own its dog, so a `var/mob/living/dog/owner`
|
||||
* might be inferior to a weakref.
|
||||
* This is also a good rule of thumb to avoid circular references, such as the
|
||||
* chew toy example. A circular reference that doesn't clean itself up properly
|
||||
* will always hard delete.
|
||||
*/
|
||||
/datum/weakref
|
||||
var/reference
|
||||
|
||||
/datum/weakref/New(datum/thing)
|
||||
reference = text_ref(thing)
|
||||
|
||||
/datum/weakref/Destroy(force)
|
||||
var/datum/target = resolve()
|
||||
qdel(target)
|
||||
|
||||
if(!force)
|
||||
return QDEL_HINT_LETMELIVE //Let BYOND autoGC thiswhen nothing is using it anymore.
|
||||
target?.weak_reference = null
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Retrieves the datum that this weakref is referencing.
|
||||
*
|
||||
* This will return `null` if the datum was deleted. This MUST be respected.
|
||||
*/
|
||||
/datum/weakref/proc/resolve()
|
||||
var/datum/D = locate(reference)
|
||||
return (!QDELETED(D) && D.weak_reference == src) ? D : null
|
||||
|
||||
/**
|
||||
* SERIOUSLY READ THE AUTODOC COMMENT FOR THIS PROC BEFORE EVEN THINKING ABOUT USING IT
|
||||
*
|
||||
* Like resolve, but doesn't care if the datum is being qdeleted but hasn't been deleted yet.
|
||||
*
|
||||
* The return value of this proc leaves hanging references if the datum is being qdeleted but hasn't been deleted yet.
|
||||
*
|
||||
* Do not do anything that would create a lasting reference to the return value, such as giving it a tag, putting it on the map,
|
||||
* adding it to an atom's contents or vis_contents, giving it a key (if it's a mob), attaching it to an atom (if it's an image),
|
||||
* or assigning it to a datum or list referenced somewhere other than a temporary value.
|
||||
*
|
||||
* Unless you're resolving a weakref to a datum in a COMSIG_QDELETING signal handler registered on that very same datum,
|
||||
* just use resolve instead.
|
||||
*/
|
||||
/datum/weakref/proc/hard_resolve()
|
||||
var/datum/D = locate(reference)
|
||||
return (D?.weak_reference == src) ? D : null
|
||||
Reference in New Issue
Block a user