File tree Expand file tree Collapse file tree 3 files changed +26
-6
lines changed
DotNext.Threading/Threading Expand file tree Collapse file tree 3 files changed +26
-6
lines changed Original file line number Diff line number Diff line change @@ -72,13 +72,15 @@ public static void ExtraListOverflow()
7272 True ( scope . Token . IsCancellationRequested ) ;
7373 }
7474
75- [ Fact ]
76- public static async Task TimeOut ( )
75+ [ Theory ]
76+ [ InlineData ( 0 ) ]
77+ [ InlineData ( 1 ) ]
78+ public static async Task TimeOut ( int timeout )
7779 {
7880 using var cts = new CancellationTokenSource ( ) ;
7981 var multiplexer = new CancellationTokenMultiplexer ( ) ;
8082
81- await using var scope = multiplexer . Combine ( TimeSpan . FromMilliseconds ( 1 ) , [ cts . Token ] ) ;
83+ await using var scope = multiplexer . Combine ( TimeSpan . FromMilliseconds ( timeout ) , [ cts . Token ] ) ;
8284 await scope . Token . WaitAsync ( ) ;
8385
8486 Equal ( scope . Token , scope . CancellationOrigin ) ;
@@ -94,7 +96,7 @@ public static async Task LazyTimeout()
9496 await using var scope = multiplexer . CombineAndSetTimeoutLater ( [ ] ) ;
9597 False ( scope . Token . IsCancellationRequested ) ;
9698
97- scope . Timeout = TimeSpan . FromMilliseconds ( 1 ) ;
99+ scope . Timeout = TimeSpan . FromMilliseconds ( 0 ) ;
98100 await scope . Token . WaitAsync ( ) ;
99101
100102 Equal ( scope . Token , scope . CancellationOrigin ) ;
Original file line number Diff line number Diff line change @@ -66,7 +66,7 @@ private static CancellationToken GetToken(MultiplexerOrToken value)
6666 /// <summary>
6767 /// Gets a value indicating that the multiplexed token is cancelled by the timeout.
6868 /// </summary>
69- public bool IsTimedOut => source ? . IsRootCause ?? false ;
69+ public bool IsTimedOut => source ? . IsRootCause ?? GetToken ( multiplexerOrToken ) == TimedOutToken ;
7070
7171 internal void SetTimeout ( TimeSpan value ) => source ? . CancelAfter ( value ) ;
7272
@@ -158,4 +158,22 @@ public TimeSpan Timeout
158158 /// <inheritdoc/>
159159 public ValueTask DisposeAsync ( ) => scope . DisposeAsync ( ) ;
160160 }
161+
162+ private static CancellationToken TimedOutToken => TimedOutTokenSource . Token ;
163+ }
164+
165+ // This source represents a canceled token that is canceled by zero timeout.
166+ // It's not possible to use new CancellationToken(canceled: true) because the multiplexer
167+ // cannot distinguish between the canceled token passed by the user code and the token that represents the timeout.
168+ // This class is not accessible by the user code, and its token cannot be passed to the multiplexer directly.
169+ file static class TimedOutTokenSource
170+ {
171+ public static readonly CancellationToken Token ;
172+
173+ static TimedOutTokenSource ( )
174+ {
175+ using var source = new CancellationTokenSource ( ) ;
176+ Token = source . Token ;
177+ source . Cancel ( ) ;
178+ }
161179}
Original file line number Diff line number Diff line change @@ -75,7 +75,7 @@ public Scope Combine(ReadOnlySpan<CancellationToken> tokens) // TODO: use params
7575 /// <exception cref="ArgumentOutOfRangeException"><paramref name="timeout"/> is negative or too large.</exception>
7676 public Scope Combine ( TimeSpan timeout , ReadOnlySpan < CancellationToken > tokens ) => timeout . Ticks switch
7777 {
78- 0L => new ( new CancellationToken ( canceled : true ) ) ,
78+ 0L => new ( TimedOutToken ) ,
7979 Timeout . InfiniteTicks => Combine ( tokens ) ,
8080 < 0L or > Timeout . MaxTimeoutParameterTicks => throw new ArgumentOutOfRangeException ( nameof ( timeout ) ) ,
8181 _ => new ( this , timeout , tokens )
You can’t perform that action at this time.
0 commit comments