public static bool OperationCanceledException_Basics() { TestHarness.TestLog("* OperationCanceledExceptionTests.OperationCanceledException_Basics()"); bool passed = true; #if !PFX_LEGACY_3_5 CancellationToken ct1 = new CancellationTokenSource().Token; OperationCanceledException ex1 = new OperationCanceledException(ct1); passed &= TestHarnessAssert.AreEqual(ct1, OCEHelper.ExtractCT(ex1), "The exception should have the CancellationToken baked in."); CancellationToken ct2 = new CancellationTokenSource().Token; OperationCanceledException ex2 = new OperationCanceledException("message", ct2); passed &= TestHarnessAssert.AreEqual(ct2, OCEHelper.ExtractCT(ex2), "The exception should have the CancellationToken baked in."); CancellationToken ct3 = new CancellationTokenSource().Token; OperationCanceledException ex3 = new OperationCanceledException("message", new Exception("inner"), ct3); passed &= TestHarnessAssert.AreEqual(ct3, OCEHelper.ExtractCT(ex3), "The exception should have the CancellationToken baked in."); #endif return(passed); }
//Identified as a possible concern in bug 544743. private static bool SemaphoreSlim_MultipleWaitersWithSeparateTokens() { TestHarness.TestLog("* SemaphoreSlimCancellationTests.SemaphoreSlim_MultipleWaitersWithSeparateTokens()"); bool passed = true; SemaphoreSlim semaphoreSlim = new SemaphoreSlim(0); // this semaphore will always be blocked for waiters. const int waitTimeoutMilliseconds = 1000; const int waitBeforeCancelMilliseconds = 300; CancellationTokenSource cts1 = new CancellationTokenSource(); CancellationTokenSource cts2 = new CancellationTokenSource(); bool wait1WokeUpNormally = false; bool wait2WokeUpNormally = false; OperationCanceledException wait1OCE = null; OperationCanceledException wait2OCE = null; int wait1ElapsedMilliseconds = -1; int wait2ElapsedMilliseconds = -1; CountdownEvent cde_allThreadsFinished = new CountdownEvent(2); //Queue up cancellation of CTS1. ThreadPool.QueueUserWorkItem( unused => { Thread.Sleep(waitBeforeCancelMilliseconds); // wait a little while. cts1.Cancel(); } ); //Queue up a wait on mres(CTS1) ThreadPool.QueueUserWorkItem( unused => { Stopwatch sw = Stopwatch.StartNew(); try { wait1WokeUpNormally = semaphoreSlim.Wait(waitTimeoutMilliseconds, cts1.Token); } catch (OperationCanceledException oce) { wait1OCE = oce; } finally { sw.Stop(); } wait1ElapsedMilliseconds = (int)sw.Elapsed.TotalMilliseconds; cde_allThreadsFinished.Signal(); } ); //Queue up a wait on mres(CTS2) ThreadPool.QueueUserWorkItem( unused => { Stopwatch sw = Stopwatch.StartNew(); try { wait2WokeUpNormally = semaphoreSlim.Wait(waitTimeoutMilliseconds, cts2.Token); } catch (OperationCanceledException oce) { wait2OCE = oce; } finally { sw.Stop(); } wait2ElapsedMilliseconds = (int)sw.Elapsed.TotalMilliseconds; cde_allThreadsFinished.Signal(); } ); cde_allThreadsFinished.Wait(); Console.WriteLine(" (first wait duration [expecting <={0,4}] ={1,4})", 500, wait1ElapsedMilliseconds); Console.WriteLine(" (second wait duration [expecting {0,4} +-50ms] ={1,4})", waitTimeoutMilliseconds, wait2ElapsedMilliseconds); passed &= TestHarnessAssert.IsFalse(wait1WokeUpNormally, "The first wait should be canceled."); passed &= TestHarnessAssert.IsNotNull(wait1OCE, "The first wait should have thrown an OCE."); passed &= TestHarnessAssert.AreEqual(cts1.Token, OCEHelper.ExtractCT(wait1OCE), "The first wait should have thrown an OCE(cts1.token)."); passed &= TestHarnessAssert.IsTrue(wait1ElapsedMilliseconds < 500, "[Warning: Timing Sensitive Test] The first wait should have canceled before 500ms elapsed."); passed &= TestHarnessAssert.IsFalse(wait2WokeUpNormally, "The second wait should not have woken up normally. It should have woken due to timeout."); passed &= TestHarnessAssert.IsNull(wait2OCE, "The second wait should not have thrown an OCE."); passed &= TestHarnessAssert.IsTrue(950 <= wait2ElapsedMilliseconds && wait2ElapsedMilliseconds <= 1050, "[Warning: Timing Sensitive Test] The second wait should have waited 1000ms +-50ms). Actual wait duration = " + wait2ElapsedMilliseconds); return(passed); }