From 17d8fe58ca7aaa2bd924050a82cf0cada39c06df Mon Sep 17 00:00:00 2001 From: SRV Date: Mon, 15 Nov 2021 07:37:33 +0200 Subject: [PATCH] Alternative fix of #60182 (#60298) --- .../System/Threading/CancellationTokenSource.cs | 39 +++++----------------- .../src/System/Threading/Timer.cs | 4 +-- 2 files changed, 10 insertions(+), 33 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs index 3f60a1c..42b9dd6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs @@ -350,19 +350,7 @@ namespace System.Threading } } - // 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); } /// @@ -392,24 +380,13 @@ namespace System.Threading // 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) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Timer.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Timer.cs index 6b7e928..108034d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Timer.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Timer.cs @@ -515,14 +515,14 @@ namespace System.Threading } } - 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; -- 2.7.4