mirror of
https://github.com/PolarisSS13/Polaris.git
synced 2026-08-31 09:08:56 +01:00
null guard qdel, better log_info_line behavior
gentle qdel refactor for readability adds ref_name and ref_type to weakref improves /proc/weakref initial test corrects weakref GC hint
This commit is contained in:
+41
-20
@@ -253,29 +253,50 @@
|
||||
/proc/key_name_admin(var/whom, var/include_name = 1)
|
||||
return key_name(whom, 1, include_name)
|
||||
|
||||
// Helper procs for building detailed log lines
|
||||
/datum/proc/log_info_line()
|
||||
return "[src] ([type])"
|
||||
|
||||
/atom/log_info_line()
|
||||
var/turf/t = get_turf(src)
|
||||
if(istype(t))
|
||||
return "([t]) ([t.x],[t.y],[t.z]) ([t.type])"
|
||||
else if(loc)
|
||||
return "([loc]) (0,0,0) ([loc.type])"
|
||||
else
|
||||
return "(NULL) (0,0,0) (NULL)"
|
||||
|
||||
/mob/log_info_line()
|
||||
return "[..()] ([ckey])"
|
||||
|
||||
/proc/log_info_line(var/datum/d)
|
||||
if(!istype(d))
|
||||
return
|
||||
return d.log_info_line()
|
||||
|
||||
/mob/proc/simple_info_line()
|
||||
return "[key_name(src)] ([x],[y],[z])"
|
||||
|
||||
|
||||
/client/proc/simple_info_line()
|
||||
return "[key_name(src)] ([mob.x],[mob.y],[mob.z])"
|
||||
|
||||
|
||||
/proc/log_info_line(datum/thing)
|
||||
if (isnull(thing))
|
||||
return "*null*"
|
||||
if (islist(thing))
|
||||
var/list/result = list()
|
||||
var/list/thing_list = thing
|
||||
for (var/key in thing_list)
|
||||
var/value = isnum(key) ? null : thing[key]
|
||||
result += "[log_info_line(key)][value ? " - [log_info_line(value)]" : ""]"
|
||||
return "\[[jointext(result, ", ")]\]"
|
||||
if (!istype(thing))
|
||||
return json_encode(thing)
|
||||
return thing.get_log_info_line()
|
||||
|
||||
|
||||
/datum/proc/get_log_info_line()
|
||||
return "[src] ([type])"
|
||||
|
||||
|
||||
/weakref/get_log_info_line()
|
||||
return "[ref_name] ([ref_type]) ([ref]) (WEAKREF)"
|
||||
|
||||
|
||||
/area/get_log_info_line()
|
||||
return "[..()] ([isnum(z) ? "[x],[y],[z]" : "0,0,0"])"
|
||||
|
||||
|
||||
/turf/get_log_info_line()
|
||||
return "[..()] ([x],[y],[z]) ([loc ? loc.type : "NULL"])"
|
||||
|
||||
|
||||
/atom/movable/get_log_info_line()
|
||||
var/turf/turf = get_turf(src)
|
||||
return "[..()] ([turf ? turf : "NULL"]) ([turf ? "[turf.x],[turf.y],[turf.z]" : "0,0,0"]) ([turf ? turf.type : "NULL"])"
|
||||
|
||||
|
||||
/mob/get_log_info_line()
|
||||
return ckey ? "[..()] ([ckey])" : ..()
|
||||
|
||||
@@ -273,71 +273,73 @@ SUBSYSTEM_DEF(garbage)
|
||||
|
||||
// Should be treated as a replacement for the 'del' keyword.
|
||||
// Datums passed to this will be given a chance to clean up references to allow the GC to collect them.
|
||||
/proc/qdel(datum/D, force=FALSE)
|
||||
if(!istype(D))
|
||||
del(D)
|
||||
/proc/qdel(datum/thing, force)
|
||||
if (!thing)
|
||||
return
|
||||
var/datum/qdel_item/I = SSgarbage.items[D.type]
|
||||
if (!I)
|
||||
I = SSgarbage.items[D.type] = new /datum/qdel_item(D.type)
|
||||
I.qdels++
|
||||
|
||||
|
||||
if(isnull(D.gc_destroyed))
|
||||
if(SEND_SIGNAL(D, COMSIG_PARENT_PREQDELETED, force)) // Give the components a chance to prevent their parent from being deleted
|
||||
if (!istype(thing))
|
||||
crash_with("qdel() can only handle /datum (sub)types, was passed: [log_info_line(thing)]")
|
||||
del(thing)
|
||||
return
|
||||
var/datum/qdel_item/qdel_item = SSgarbage.items[thing.type]
|
||||
if (!qdel_item)
|
||||
qdel_item = new (thing.type)
|
||||
SSgarbage.items[thing.type] = qdel_item
|
||||
qdel_item.qdels++
|
||||
if (isnull(thing.gc_destroyed))
|
||||
if (SEND_SIGNAL(thing, COMSIG_PARENT_PREQDELETED, force)) // Give the components a chance to prevent their parent from being deleted
|
||||
return
|
||||
D.gc_destroyed = GC_CURRENTLY_BEING_QDELETED
|
||||
thing.gc_destroyed = GC_CURRENTLY_BEING_QDELETED
|
||||
var/start_time = world.time
|
||||
var/start_tick = world.tick_usage
|
||||
SEND_SIGNAL(D, COMSIG_PARENT_QDELETING, force) // Let the (remaining) components know about the result of Destroy
|
||||
var/hint = D.Destroy(force) // Let our friend know they're about to get fucked up.
|
||||
if(world.time != start_time)
|
||||
I.slept_destroy++
|
||||
SEND_SIGNAL(thing, COMSIG_PARENT_QDELETING, force) // Let the (remaining) components know about the result of Destroy
|
||||
var/hint = thing.Destroy(force) // Let our friend know they're about to get fucked up.
|
||||
if (world.time != start_time)
|
||||
qdel_item.slept_destroy++
|
||||
else
|
||||
I.destroy_time += TICK_USAGE_TO_MS(start_tick)
|
||||
if(!D)
|
||||
qdel_item.destroy_time += TICK_USAGE_TO_MS(start_tick)
|
||||
if (!thing)
|
||||
return
|
||||
switch(hint)
|
||||
switch (hint)
|
||||
if (QDEL_HINT_QUEUE) //qdel should queue the object for deletion.
|
||||
SSgarbage.PreQueue(D)
|
||||
SSgarbage.PreQueue(thing)
|
||||
if (QDEL_HINT_IWILLGC)
|
||||
D.gc_destroyed = world.time
|
||||
thing.gc_destroyed = world.time
|
||||
return
|
||||
if (QDEL_HINT_LETMELIVE) //qdel should let the object live after calling destory.
|
||||
if(!force)
|
||||
D.gc_destroyed = null //clear the gc variable (important!)
|
||||
thing.gc_destroyed = null //clear the gc variable (important!)
|
||||
return
|
||||
// Returning LETMELIVE after being told to force destroy
|
||||
// indicates the objects Destroy() does not respect force
|
||||
#ifdef TESTING
|
||||
if(!I.no_respect_force)
|
||||
crash_with("[D.type] has been force deleted, but is \
|
||||
#ifdef TESTING
|
||||
if(!qdel_item.no_respect_force)
|
||||
crash_with("[thing.type] has been force deleted, but is \
|
||||
returning an immortal QDEL_HINT, indicating it does \
|
||||
not respect the force flag for qdel(). It has been \
|
||||
placed in the queue, further instances of this type \
|
||||
will also be queued.")
|
||||
#endif
|
||||
I.no_respect_force++
|
||||
|
||||
SSgarbage.PreQueue(D)
|
||||
#endif
|
||||
qdel_item.no_respect_force++
|
||||
SSgarbage.PreQueue(thing)
|
||||
if (QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete using a hard reference to save time from the locate()
|
||||
SSgarbage.HardQueue(D)
|
||||
SSgarbage.HardQueue(thing)
|
||||
if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste.
|
||||
SSgarbage.HardDelete(D)
|
||||
SSgarbage.HardDelete(thing)
|
||||
if (QDEL_HINT_FINDREFERENCE)//qdel will, if TESTING is enabled, display all references to this object, then queue the object for deletion.
|
||||
SSgarbage.PreQueue(D)
|
||||
SSgarbage.PreQueue(thing)
|
||||
#ifdef TESTING
|
||||
D.find_references()
|
||||
thing.find_references()
|
||||
#endif
|
||||
else
|
||||
#ifdef TESTING
|
||||
if(!I.no_hint)
|
||||
crash_with("[D.type] is not returning a qdel hint. It is being placed in the queue. Further instances of this type will also be queued.")
|
||||
if (!qdel_item.no_hint)
|
||||
crash_with("[thing.type] is not returning a qdel hint. It is being placed in the queue. Further instances of this type will also be queued.")
|
||||
#endif
|
||||
I.no_hint++
|
||||
SSgarbage.PreQueue(D)
|
||||
else if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
|
||||
CRASH("[D.type] destroy proc was called multiple times, likely due to a qdel loop in the Destroy logic")
|
||||
qdel_item.no_hint++
|
||||
SSgarbage.PreQueue(thing)
|
||||
else if (thing.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
|
||||
CRASH("[thing.type] destroy proc was called multiple times, likely due to a qdel loop in the Destroy logic")
|
||||
|
||||
|
||||
#ifdef TESTING
|
||||
|
||||
|
||||
+23
-19
@@ -1,26 +1,30 @@
|
||||
//obtain a weak reference to a datum
|
||||
/proc/weakref(datum/D)
|
||||
if(!istype(D))
|
||||
return
|
||||
if(QDELETED(D))
|
||||
return
|
||||
if(!D.weakref)
|
||||
D.weakref = new/weakref(D)
|
||||
return D.weakref
|
||||
|
||||
/weakref
|
||||
var/ref
|
||||
var/ref_name
|
||||
var/ref_type
|
||||
|
||||
/weakref/New(datum/D)
|
||||
ref = "\ref[D]"
|
||||
|
||||
/weakref/Destroy()
|
||||
// A weakref datum should not be manually destroyed as it is a shared resource,
|
||||
// rather it should be automatically collected by the BYOND GC when all references are gone.
|
||||
return QDEL_HINT_LETMELIVE
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
return QDEL_HINT_IWILLGC
|
||||
|
||||
|
||||
/weakref/New(datum/thing)
|
||||
ref = "\ref[thing]"
|
||||
ref_name = "[thing]"
|
||||
ref_type = thing.type
|
||||
|
||||
|
||||
/weakref/proc/resolve()
|
||||
var/datum/D = locate(ref)
|
||||
if(D && D.weakref == src)
|
||||
return D
|
||||
return null
|
||||
var/datum/thing = locate(ref)
|
||||
if (thing && thing.weakref == src)
|
||||
return thing
|
||||
return null
|
||||
|
||||
|
||||
/proc/weakref(datum/thing)
|
||||
if (!istype(thing) || QDELING(thing))
|
||||
return
|
||||
if (!thing.weakref)
|
||||
thing.weakref = new /weakref (thing)
|
||||
return thing.weakref
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
var/fail = FALSE
|
||||
for(var/atom/atom in world)
|
||||
if(!atom.initialized && !QDELETED(atom)) // Not ideal to skip over qdeleted atoms, but a lot of current code uses pre-init qdels
|
||||
log_bad("Uninitialized atom: [atom.type] - [atom.log_info_line()]")
|
||||
log_bad("Uninitialized atom: [atom.type] - [atom.get_log_info_line()]")
|
||||
fail = TRUE
|
||||
if(fail)
|
||||
fail("There were uninitialized atoms.")
|
||||
|
||||
Reference in New Issue
Block a user