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:
Fluffy
2024-01-15 14:08:27 +00:00
committed by GitHub
parent 0c8bdbdd68
commit ca6b04e1d7
125 changed files with 1574 additions and 805 deletions
+50 -24
View File
@@ -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]
-3
View File
@@ -1,4 +1 @@
/****************
* Debug Support *
****************/
GLOBAL_LIST_EMPTY(all_observable_events)
+71
View File
@@ -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
-17
View File
@@ -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
+95
View File
@@ -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