From 7d3be0e838d89b6d9d92f619361005767e495c7e Mon Sep 17 00:00:00 2001 From: Fox McCloud Date: Sat, 20 Oct 2018 00:49:55 -0400 Subject: [PATCH] Updates the Garbage SS --- code/__DEFINES/components.dm | 3 +- code/__DEFINES/qdel.dm | 10 ++-- code/controllers/subsystem/garbage.dm | 67 +++++++-------------------- 3 files changed, 24 insertions(+), 56 deletions(-) diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm index 6f14b75b2ec..967749a55a7 100644 --- a/code/__DEFINES/components.dm +++ b/code/__DEFINES/components.dm @@ -17,7 +17,8 @@ // /datum signals #define COMSIG_COMPONENT_ADDED "component_added" //when a component is added to a datum: (/datum/component) #define COMSIG_COMPONENT_REMOVING "component_removing" //before a component is removed from a datum because of RemoveComponent: (/datum/component) -#define COMSIG_PARENT_QDELETED "parent_qdeleted" //before a datum's Destroy() is called: () +#define COMSIG_PARENT_PREQDELETED "parent_preqdeleted" //before a datum's Destroy() is called: (force), returning a nonzero value will cancel the qdel operation +#define COMSIG_PARENT_QDELETED "parent_qdeleted" //after a datum's Destroy() is called: (force, qdel_hint), at this point none of the other components chose to interrupt qdel and Destroy has been called // /atom signals #define COMSIG_PARENT_ATTACKBY "atom_attackby" //from base of atom/attackby(): (/obj/item, /mob/living, params) diff --git a/code/__DEFINES/qdel.dm b/code/__DEFINES/qdel.dm index 8d504edaf41..6adb876da8d 100644 --- a/code/__DEFINES/qdel.dm +++ b/code/__DEFINES/qdel.dm @@ -11,14 +11,12 @@ #define QDEL_HINT_IFFAIL_FINDREFERENCE 6 //Above but only if gc fails. //defines for the gc_destroyed var -#define GC_QUEUE_PREQUEUE 1 -#define GC_QUEUE_CHECK 2 -#define GC_QUEUE_HARDDELETE 3 -#define GC_QUEUE_COUNT 3 //increase this when adding more steps. +#define GC_QUEUE_CHECK 1 +#define GC_QUEUE_HARDDELETE 2 +#define GC_QUEUE_COUNT 2 //increase this when adding more steps. #define GC_QUEUED_FOR_QUEUING -1 -#define GC_QUEUED_FOR_HARD_DEL -2 -#define GC_CURRENTLY_BEING_QDELETED -3 +#define GC_CURRENTLY_BEING_QDELETED -2 #define QDELING(X) (X.gc_destroyed) #define QDELETED(X) (!X || QDELING(X)) diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index 97dd02838d0..c1cb90919f5 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -59,7 +59,6 @@ SUBSYSTEM_DEF(garbage) msg += " | Fail:[fail_counts.Join(",")]" ..(msg) - /datum/controller/subsystem/garbage/Shutdown() //Adds the del() log to the qdel log file var/list/dellog = list() @@ -86,41 +85,21 @@ SUBSYSTEM_DEF(garbage) /datum/controller/subsystem/garbage/fire() //the fact that this resets its processing each fire (rather then resume where it left off) is intentional. - var/queue = GC_QUEUE_PREQUEUE + var/queue = GC_QUEUE_CHECK while(state == SS_RUNNING) switch(queue) - if(GC_QUEUE_PREQUEUE) - HandlePreQueue() - queue = GC_QUEUE_PREQUEUE + 1 if(GC_QUEUE_CHECK) HandleQueue(GC_QUEUE_CHECK) queue = GC_QUEUE_CHECK + 1 if(GC_QUEUE_HARDDELETE) HandleQueue(GC_QUEUE_HARDDELETE) + if(state == SS_PAUSED) //make us wait again before the next run. + state = SS_RUNNING break - if(state == SS_PAUSED) //make us wait again before the next run. - state = SS_RUNNING -//If you see this proc high on the profile, what you are really seeing is the garbage collection/soft delete overhead in byond. -//Don't attempt to optimize, not worth the effort. -/datum/controller/subsystem/garbage/proc/HandlePreQueue() - var/list/tobequeued = queues[GC_QUEUE_PREQUEUE] - var/static/count = 0 - if(count) - var/c = count - count = 0 //so if we runtime on the Cut, we don't try again. - tobequeued.Cut(1, c + 1) - for(var/ref in tobequeued) - count++ - Queue(ref, GC_QUEUE_PREQUEUE + 1) - if(MC_TICK_CHECK) - break - if(count) - tobequeued.Cut(1, count + 1) - count = 0 /datum/controller/subsystem/garbage/proc/HandleQueue(level = GC_QUEUE_CHECK) if(level == GC_QUEUE_CHECK) @@ -142,7 +121,7 @@ SUBSYSTEM_DEF(garbage) if(!refID) count++ if(MC_TICK_CHECK) - break + return continue var/GCd_at_time = queue[refID] @@ -161,7 +140,7 @@ SUBSYSTEM_DEF(garbage) reference_find_on_fail -= refID //It's deleted we don't care anymore. #endif if(MC_TICK_CHECK) - break + return continue // Something's still referring to the qdel'd object. @@ -184,27 +163,20 @@ SUBSYSTEM_DEF(garbage) if(GC_QUEUE_HARDDELETE) HardDelete(D) if(MC_TICK_CHECK) - break + return continue Queue(D, level + 1) if(MC_TICK_CHECK) - break + return if(count) queue.Cut(1, count + 1) count = 0 -/datum/controller/subsystem/garbage/proc/PreQueue(datum/D) - if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) - queues[GC_QUEUE_PREQUEUE] += D - D.gc_destroyed = GC_QUEUED_FOR_QUEUING - /datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_CHECK) if(isnull(D)) return - if(D.gc_destroyed == GC_QUEUED_FOR_HARD_DEL) - level = GC_QUEUE_HARDDELETE if(level > GC_QUEUE_COUNT) HardDelete(D) return @@ -250,11 +222,6 @@ SUBSYSTEM_DEF(garbage) message_admins("Error: [type]([refID]) took longer than 1 second to delete (took [time / 10] seconds to delete).") postpone(time) -/datum/controller/subsystem/garbage/proc/HardQueue(datum/D) - if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) - queues[GC_QUEUE_PREQUEUE] += D - D.gc_destroyed = GC_QUEUED_FOR_HARD_DEL - /datum/controller/subsystem/garbage/Recover() if(istype(SSgarbage.queues)) for(var/i in 1 to SSgarbage.queues.len) @@ -294,11 +261,13 @@ SUBSYSTEM_DEF(garbage) if(isnull(D.gc_destroyed)) - D.SendSignal(COMSIG_PARENT_QDELETED) + if(D.SendSignal(COMSIG_PARENT_PREQDELETED, force)) // Give the components a chance to prevent their parent from being deleted + return D.gc_destroyed = GC_CURRENTLY_BEING_QDELETED var/start_time = world.time var/start_tick = world.tick_usage var/hint = D.Destroy(arglist(args.Copy(2))) // Let our friend know they're about to get fucked up. + D.SendSignal(COMSIG_PARENT_QDELETED, force, hint) // Let the (remaining) components know about the result of Destroy if(world.time != start_time) I.slept_destroy++ else @@ -307,7 +276,7 @@ SUBSYSTEM_DEF(garbage) return switch(hint) if(QDEL_HINT_QUEUE) //qdel should queue the object for deletion. - SSgarbage.PreQueue(D) + SSgarbage.Queue(D) if(QDEL_HINT_IWILLGC) D.gc_destroyed = world.time return @@ -327,18 +296,18 @@ SUBSYSTEM_DEF(garbage) #endif I.no_respect_force++ - SSgarbage.PreQueue(D) - 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.Queue(D) + if(QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete + SSgarbage.Queue(D, GC_QUEUE_HARDDELETE) if(QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste. SSgarbage.HardDelete(D) 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.Queue(D) #ifdef TESTING D.find_references() #endif if(QDEL_HINT_IFFAIL_FINDREFERENCE) - SSgarbage.PreQueue(D) + SSgarbage.Queue(D) #ifdef TESTING SSgarbage.reference_find_on_fail["\ref[D]"] = TRUE #endif @@ -348,7 +317,7 @@ SUBSYSTEM_DEF(garbage) testing("WARNING: [D.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) + SSgarbage.Queue(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") @@ -463,4 +432,4 @@ SUBSYSTEM_DEF(garbage) CHECK_TICK #endif -#endif +#endif \ No newline at end of file