Skip to content

Commit

Permalink
Alternative fix of #60182 (#60298)
Browse files Browse the repository at this point in the history
  • Loading branch information
sakno authored Nov 15, 2021
1 parent 233c65d commit 17d8fe5
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -350,19 +350,7 @@ private void CancelAfter(uint millisecondsDelay)
}
}

// It is possible that _timer has already been disposed, so we must do
// the following in a try/catch block.
try
{
timer.Change(millisecondsDelay, Timeout.UnsignedInfinite);
}
catch (ObjectDisposedException)
{
// Just eat the exception. There is no other way to tell that
// the timer has been disposed, and even if there were, there
// would not be a good way to deal with the observe/dispose
// race condition.
}
timer.Change(millisecondsDelay, Timeout.UnsignedInfinite, throwIfDisposed: false);
}

/// <summary>
Expand Down Expand Up @@ -392,24 +380,13 @@ public bool TryReset()
// to transition from canceled to non-canceled.
if (_state == NotCanceledState)
{
bool reset = false;

try
{
// If there is no timer, then we're free to reset. If there is a timer, then we need to first try
// to reset it to be infinite so that it won't fire, and then recognize that it could have already
// fired by the time we successfully changed it, and so check to see whether that's possibly the case.
// If we successfully reset it and it never fired, then we can be sure it won't trigger cancellation.
reset = _timer is not TimerQueueTimer timer ||
(timer.Change(Timeout.UnsignedInfinite, Timeout.UnsignedInfinite) && !timer._everQueued);
}
catch (ObjectDisposedException)
{
// Just eat the exception. There is no other way to tell that
// the timer has been disposed, and even if there were, there
// would not be a good way to deal with the observe/dispose
// race condition.
}
// If there is no timer, then we're free to reset. If there is a timer, then we need to first try
// to reset it to be infinite so that it won't fire, and then recognize that it could have already
// fired by the time we successfully changed it, and so check to see whether that's possibly the case.
// If we successfully reset it and it never fired, then we can be sure it won't trigger cancellation.
bool reset =
_timer is not TimerQueueTimer timer ||
(timer.Change(Timeout.UnsignedInfinite, Timeout.UnsignedInfinite, throwIfDisposed: false) && !timer._everQueued);

if (reset)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -515,14 +515,14 @@ internal string DisplayString
}
}

internal bool Change(uint dueTime, uint period)
internal bool Change(uint dueTime, uint period, bool throwIfDisposed = true)
{
bool success;

lock (_associatedTimerQueue)
{
if (_canceled)
throw new ObjectDisposedException(null, SR.ObjectDisposed_Generic);
return throwIfDisposed ? throw new ObjectDisposedException(null, SR.ObjectDisposed_Generic) : false;

_period = period;

Expand Down

0 comments on commit 17d8fe5

Please sign in to comment.