diff --git a/Projects/Server/Timer/Timer.DelayCall.cs b/Projects/Server/Timer/Timer.DelayCall.cs index 81fb9d5b6..5d98180bb 100644 --- a/Projects/Server/Timer/Timer.DelayCall.cs +++ b/Projects/Server/Timer/Timer.DelayCall.cs @@ -71,7 +71,7 @@ namespace Server public static void StartTimer(TimeSpan delay, TimeSpan interval, int count, Action callback) { DelayCallTimer t = DelayCallTimer.GetTimer(delay, interval, count, callback); - t._selfReturn = true; + t._returnOnDetach = true; t.Start(); #if DEBUG_TIMERS @@ -115,7 +115,7 @@ namespace Server public sealed class DelayCallTimer : Timer, INotifyCompletion { - internal bool _selfReturn; + internal bool _returnOnDetach; #if DEBUG_TIMERS internal bool _allowFinalization; #endif @@ -143,17 +143,7 @@ namespace Server _continuation?.Invoke(); } - public override void Stop() - { - base.Stop(); - - if (_selfReturn) - { - Return(); - } - } - - internal void Return() + internal override void OnDetach() { if (Running) { @@ -161,39 +151,42 @@ namespace Server return; } - Version++; // Increment the version so if this is called from OnTick() and another timer is started, we don't have a problem - -#if DEBUG_TIMERS - _stackTraces.Remove(GetHashCode()); -#endif - - if (_poolCount >= _poolCapacity) + if (_returnOnDetach) { -#if DEBUG_TIMERS - logger.Warning($"DelayCallTimer pool reached maximum of {_poolCapacity} timers"); - _allowFinalization = true; -#endif - return; - } + // Increment the version so if this is called from OnTick() and another timer is started, we don't have a problem + // Version++; - _continuation = null; - ReturnToPool(1, this, this); +#if DEBUG_TIMERS + _stackTraces.Remove(GetHashCode()); +#endif + + if (_poolCount >= _poolCapacity) + { +#if DEBUG_TIMERS + logger.Warning($"DelayCallTimer pool reached maximum of {_poolCapacity} timers"); + _allowFinalization = true; +#endif + return; + } + + _continuation = null; + _returnOnDetach = false; + ReturnToPool(1, this, this); + } } public static DelayCallTimer GetTimer(TimeSpan delay, TimeSpan interval, int count, Action callback) { - if (_poolHead != null) + var timer = GetFromPool(); + if (timer != null) { - _poolCount--; #if DEBUG_TIMERS - logger.Information($"Pool count: {_poolCount} / {_poolCapacity}"); + logger.Information($"Getting from pool: ({_poolCount} / {_poolCapacity})"); #endif - var timer = GetFromPool(); - timer.Init(delay, interval, count); timer._continuation = callback; - timer._selfReturn = false; + timer._returnOnDetach = false; #if DEBUG_TIMERS timer._allowFinalization = false; #endif diff --git a/Projects/Server/Timer/Timer.Pool.cs b/Projects/Server/Timer/Timer.Pool.cs index a7db9c273..cb92fc18f 100644 --- a/Projects/Server/Timer/Timer.Pool.cs +++ b/Projects/Server/Timer/Timer.Pool.cs @@ -62,22 +62,29 @@ namespace Server _poolHead = head; _poolCount += amount; #if DEBUG_TIMERS - logger.Information($"Pool count: {_poolCount} / {_poolCapacity}"); + logger.Information($"Returning to pool. ({_poolCount} / {_poolCapacity})"); #endif } private static DelayCallTimer GetFromPool() { + if (_poolHead == null) + { + return null; + } + var timer = _poolHead; _poolHead = _poolHead._nextTimer as DelayCallTimer; timer.Detach(); + _poolCount--; + return timer; } internal static void RefillPool(int amount, out DelayCallTimer head, out DelayCallTimer tail) { #if DEBUG_TIMERS - logger.Information($"Filling pool with {amount} timers."); + logger.Information($"Filling pool with {amount} timers."); #endif head = null; diff --git a/Projects/Server/Timer/Timer.TimerWheel.cs b/Projects/Server/Timer/Timer.TimerWheel.cs index 5389eb557..f8e4e451c 100644 --- a/Projects/Server/Timer/Timer.TimerWheel.cs +++ b/Projects/Server/Timer/Timer.TimerWheel.cs @@ -113,6 +113,11 @@ namespace Server } } + if (!timer.Running) + { + timer.OnDetach(); + } + timer = next; } while (timer != null); } @@ -150,7 +155,7 @@ namespace Server private static void AddTimer(Timer timer, long delay) { #if DEBUG_TIMERS - var originalDelay = delay + var originalDelay = delay; #endif delay = Math.Max(0, delay); diff --git a/Projects/Server/Timer/Timer.cs b/Projects/Server/Timer/Timer.cs index 5ed8ac3d9..786d1c86c 100644 --- a/Projects/Server/Timer/Timer.cs +++ b/Projects/Server/Timer/Timer.cs @@ -116,8 +116,8 @@ namespace Server Running = false; Version++; - var prof = GetProfile(); + var prof = GetProfile(); if (prof != null) { prof.Stopped++; @@ -152,5 +152,9 @@ namespace Server _nextTimer = null; _prevTimer = null; } + + internal virtual void OnDetach() + { + } } } diff --git a/Projects/Server/Timer/TimerExecutionToken.cs b/Projects/Server/Timer/TimerExecutionToken.cs index 9535e726e..9e9992e3b 100644 --- a/Projects/Server/Timer/TimerExecutionToken.cs +++ b/Projects/Server/Timer/TimerExecutionToken.cs @@ -50,9 +50,12 @@ namespace Server public void Cancel() { - _timer?.Stop(); - _timer?.Return(); - _timer = null; + if (_timer != null) + { + _timer._returnOnDetach = true; + _timer?.Stop(); + _timer = null; + } this = default; } diff --git a/Projects/Server/World/World.cs b/Projects/Server/World/World.cs index 53968cce2..142b554a2 100644 --- a/Projects/Server/World/World.cs +++ b/Projects/Server/World/World.cs @@ -132,7 +132,7 @@ namespace Server public static WorldState WorldState { get; private set; } public static bool Saving => WorldState == WorldState.Saving; - public static bool Running => WorldState == WorldState.Running; + public static bool Running => WorldState is not WorldState.Loading and not WorldState.Initial; public static bool Loading => WorldState == WorldState.Loading; public static Dictionary Mobiles { get; private set; } diff --git a/Projects/UOContent/World Saves/AutoSave.cs b/Projects/UOContent/World Saves/AutoSave.cs index a97446d89..96051e6a1 100644 --- a/Projects/UOContent/World Saves/AutoSave.cs +++ b/Projects/UOContent/World Saves/AutoSave.cs @@ -77,7 +77,7 @@ namespace Server.Saves return; } - if (SavesEnabled && !AutoRestart.Restarting && !Core.Closing && World.Running) + if (SavesEnabled && !AutoRestart.Restarting && !Core.Closing && !World.Saving) { if (Warning > TimeSpan.Zero) {