fix: Fixes pooled timers orphaning each other (#809)

This commit is contained in:
Kamron Batman 2021-10-03 22:58:46 -07:00 • committed by GitHub
parent 8e4d5bb169
commit 4893094bb4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 55 additions and 43 deletions

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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()
{
}
}
}

View file

@ -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;
}

View file

@ -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<Serial, Mobile> Mobiles { get; private set; }

View file

@ -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)
{