fix: Fixes pooled timers orphaning each other (#809)
This commit is contained in:
parent
8e4d5bb169
commit
4893094bb4
7 changed files with 55 additions and 43 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue