Alternative fix of #60182 (#60298)
authorSRV <roman.sakno@gmail.com>
Mon, 15 Nov 2021 05:37:33 +0000 (07:37 +0200)
committerGitHub <noreply@github.com>
Mon, 15 Nov 2021 05:37:33 +0000 (22:37 -0700)
src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs
src/libraries/System.Private.CoreLib/src/System/Threading/Timer.cs

index 3f60a1c..42b9dd6 100644 (file)
@@ -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);
         }
 
         /// <summary>
@@ -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)
                 {
index 6b7e928..108034d 100644 (file)
@@ -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;