1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Threading.Tasks;
6 using Xunit;
7 
8 namespace System.Threading.Tests
9 {
10     public static class SemaphoreSlimCancellationTests
11     {
12         [Fact]
CancelBeforeWait()13         public static void CancelBeforeWait()
14         {
15             SemaphoreSlim semaphoreSlim = new SemaphoreSlim(2);
16 
17             CancellationTokenSource cs = new CancellationTokenSource();
18             cs.Cancel();
19             CancellationToken ct = cs.Token;
20 
21             const int millisec = 100;
22             TimeSpan timeSpan = new TimeSpan(100);
23             EnsureOperationCanceledExceptionThrown(() => semaphoreSlim.Wait(ct), ct, "CancelBeforeWait:  An OCE should have been thrown.");
24             EnsureOperationCanceledExceptionThrown(() => semaphoreSlim.Wait(millisec, ct), ct, "CancelBeforeWait:  An OCE should have been thrown.");
25             EnsureOperationCanceledExceptionThrown(() => semaphoreSlim.Wait(timeSpan, ct), ct, "CancelBeforeWait:  An OCE should have been thrown.");
26             semaphoreSlim.Dispose();
27         }
28 
29         [Fact]
CancelAfterWait()30         public static void CancelAfterWait()
31         {
32             CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
33             CancellationToken cancellationToken = cancellationTokenSource.Token;
34 
35             SemaphoreSlim semaphoreSlim = new SemaphoreSlim(0); // semaphore that will block all waiters
36 
37             Task.Run(
38                 () =>
39                 {
40                     for (int i = 0; i < 300; i++) ;
41                     cancellationTokenSource.Cancel();
42                 });
43 
44             //Now wait.. the wait should abort and an exception should be thrown
45             EnsureOperationCanceledExceptionThrown(
46                () => semaphoreSlim.Wait(cancellationToken),
47                cancellationToken, "CancelAfterWait:  An OCE(null) should have been thrown that references the cancellationToken.");
48 
49             // the token should not have any listeners.
50             // currently we don't expose this.. but it was verified manually
51         }
52 
EnsureOperationCanceledExceptionThrown(Action action, CancellationToken token, string message)53         private static void EnsureOperationCanceledExceptionThrown(Action action, CancellationToken token, string message)
54         {
55             OperationCanceledException operationCanceledEx =
56                 Assert.Throws<OperationCanceledException>(action);
57             Assert.Equal(token, operationCanceledEx.CancellationToken);
58         }
59     }
60 }
61