1- using System . Runtime . CompilerServices ;
21using System . Runtime . InteropServices ;
32using Debug = System . Diagnostics . Debug ;
43
@@ -7,13 +6,13 @@ namespace DotNext.Threading.Tasks.Pooling;
76/*
87 * Represents a pool without any allocations. Assuming that wait queues are organized using
98 * linked nodes where each node is a completion source. If so, the node pointers (next/previous)
10- * can be used to keep completion sources in the pool. The implementation is thread-safe .
9+ * can be used to keep completion sources in the pool. The access must be synchronized .
1110 */
1211[ StructLayout ( LayoutKind . Auto ) ]
1312internal struct ValueTaskPool < T > ( long maximumRetained )
1413{
15- private volatile LinkedValueTaskCompletionSource < T > ? first ;
16- private long count ; // volatile
14+ private LinkedValueTaskCompletionSource < T > ? first ;
15+ private long count ;
1716
1817 public ValueTaskPool ( )
1918 : this ( long . MaxValue )
@@ -27,54 +26,33 @@ public void Return(LinkedValueTaskCompletionSource<T> node)
2726 Debug . Assert ( node is { Status : ManualResetCompletionSourceStatus . WaitForActivation } ) ;
2827 Debug . Assert ( node is { Next : null , Previous : null } ) ;
2928
30- // try to increment the counter
31- for ( long current = Atomic . Read ( in count ) , tmp ; current < maximumRetained ; current = tmp )
29+ if ( count < maximumRetained )
3230 {
33- tmp = Interlocked . CompareExchange ( ref count , current + 1L , current ) ;
34- if ( tmp == current )
35- {
36- ReturnCore ( node ) ;
37- break ;
38- }
39- }
40- }
41-
42- private void ReturnCore ( LinkedValueTaskCompletionSource < T > node )
43- {
44- for ( LinkedValueTaskCompletionSource < T > ? current = first , tmp ; ; current = tmp )
45- {
46- node . Next = current ;
47-
48- tmp = Interlocked . CompareExchange ( ref first , node , current ) ;
49- if ( ReferenceEquals ( tmp , current ) )
50- break ;
31+ node . Next = first ;
32+ first = node ;
33+ count ++ ;
5134 }
5235 }
5336
5437 public TNode Rent < TNode > ( )
5538 where TNode : LinkedValueTaskCompletionSource < T > , new ( )
5639 {
57- var current = first ;
58- for ( LinkedValueTaskCompletionSource < T > ? tmp ; ; current = Unsafe . As < TNode > ( tmp ) )
40+ if ( first is TNode result )
5941 {
60- if ( current is null )
61- {
62- current = new TNode ( ) ;
63- break ;
64- }
42+ first = result . Next ;
43+ result . Next = null ;
44+ count -- ;
6545
66- tmp = Interlocked . CompareExchange ( ref first , current . Next , current ) ;
67- if ( ! ReferenceEquals ( tmp , current ) )
68- continue ;
46+ Debug . Assert ( count >= 0L ) ;
47+ Debug . Assert ( count is 0L || first is not null ) ;
48+ }
49+ else
50+ {
51+ Debug . Assert ( count is 0L ) ;
6952
70- current . Next = null ;
71- var actualCount = Interlocked . Decrement ( ref count ) ;
72- Debug . Assert ( actualCount >= 0L ) ;
73- break ;
53+ result = new ( ) ;
7454 }
7555
76- Debug . Assert ( current is TNode ) ;
77- Debug . Assert ( current is { Next : null , Previous : null } ) ;
78- return Unsafe . As < TNode > ( current ) ;
56+ return result ;
7957 }
8058}
0 commit comments