1
+ #if NETSTANDARD2_1 || NETCOREAPP3_0
2
+ #define VALUETASKSOURCE
3
+ #endif
4
+
1
5
using System ;
2
6
using System . Net . Sockets ;
3
7
using System . Threading . Tasks ;
8
+ #if VALUETASKSOURCE
9
+ using System . Threading . Tasks . Sources ;
10
+ #endif
4
11
using MySql . Data . MySqlClient ;
5
12
using MySqlConnector . Utilities ;
6
13
7
14
namespace MySqlConnector . Protocol . Serialization
8
15
{
9
16
internal sealed class SocketByteHandler : IByteHandler
17
+ #if VALUETASKSOURCE
18
+ , IValueTaskSource < int >
19
+ #endif
10
20
{
11
21
public SocketByteHandler ( Socket socket )
12
22
{
13
23
m_socket = socket ;
14
- var socketEventArgs = new SocketAsyncEventArgs ( ) ;
15
- m_socketAwaitable = new SocketAwaitable ( socketEventArgs ) ;
24
+ #if VALUETASKSOURCE
25
+ m_valueTaskSource = new ManualResetValueTaskSourceCore < int > { RunContinuationsAsynchronously = true } ;
26
+ m_socketEventArgs = new SocketAsyncEventArgs ( ) ;
27
+ m_socketEventArgs . Completed += ( s , e ) => PropagateSocketAsyncEventArgsStatus ( ) ;
28
+ #else
29
+ m_socketAwaitable = new SocketAwaitable ( new SocketAsyncEventArgs ( ) ) ;
30
+ #endif
16
31
m_closeSocket = socket . Dispose ;
17
32
RemainingTimeout = Constants . InfiniteTimeout ;
18
33
}
19
34
35
+ #if VALUETASKSOURCE
36
+ public void Dispose ( ) => m_socketEventArgs . Dispose ( ) ;
37
+ #else
20
38
public void Dispose ( ) => m_socketAwaitable . EventArgs . Dispose ( ) ;
39
+ #endif
21
40
22
41
public int RemainingTimeout { get ; set ; }
23
42
24
- public ValueTask < int > ReadBytesAsync ( ArraySegment < byte > buffer , IOBehavior ioBehavior )
25
- {
26
- return ioBehavior == IOBehavior . Asynchronous ?
27
- new ValueTask < int > ( DoReadBytesAsync ( buffer ) ) : DoReadBytesSync ( buffer ) ;
28
- }
43
+ public ValueTask < int > ReadBytesAsync ( ArraySegment < byte > buffer , IOBehavior ioBehavior ) =>
44
+ ioBehavior == IOBehavior . Asynchronous ? DoReadBytesAsync ( buffer ) : DoReadBytesSync ( buffer ) ;
29
45
30
46
private ValueTask < int > DoReadBytesSync ( ArraySegment < byte > buffer )
31
47
{
@@ -53,18 +69,16 @@ private ValueTask<int> DoReadBytesSync(ArraySegment<byte> buffer)
53
69
}
54
70
}
55
71
56
- private async Task < int > DoReadBytesAsync ( ArraySegment < byte > buffer )
72
+ private async ValueTask < int > DoReadBytesAsync ( ArraySegment < byte > buffer )
57
73
{
58
74
var startTime = RemainingTimeout == Constants . InfiniteTimeout ? 0 : Environment . TickCount ;
59
75
var timerId = RemainingTimeout == Constants . InfiniteTimeout ? 0 :
60
76
RemainingTimeout <= 0 ? throw MySqlException . CreateForTimeout ( ) :
61
77
TimerQueue . Instance . Add ( RemainingTimeout , m_closeSocket ) ;
62
- m_socketAwaitable . EventArgs . SetBuffer ( buffer . Array , buffer . Offset , buffer . Count ) ;
63
78
int bytesRead ;
64
79
try
65
80
{
66
- await m_socket . ReceiveAsync ( m_socketAwaitable ) ;
67
- bytesRead = m_socketAwaitable . EventArgs . BytesTransferred ;
81
+ bytesRead = await ReadBytesFromSocketAsync ( buffer ) . ConfigureAwait ( false ) ;
68
82
}
69
83
catch ( SocketException ex )
70
84
{
@@ -88,7 +102,7 @@ private async Task<int> DoReadBytesAsync(ArraySegment<byte> buffer)
88
102
public ValueTask < int > WriteBytesAsync ( ArraySegment < byte > data , IOBehavior ioBehavior )
89
103
{
90
104
if ( ioBehavior == IOBehavior . Asynchronous )
91
- return new ValueTask < int > ( DoWriteBytesAsync ( data ) ) ;
105
+ return WriteBytesToSocketAsync ( data ) ;
92
106
93
107
try
94
108
{
@@ -101,15 +115,62 @@ public ValueTask<int> WriteBytesAsync(ArraySegment<byte> data, IOBehavior ioBeha
101
115
}
102
116
}
103
117
104
- private async Task < int > DoWriteBytesAsync ( ArraySegment < byte > data )
118
+ #if VALUETASKSOURCE
119
+ private ValueTask < int > ReadBytesFromSocketAsync ( ArraySegment < byte > buffer )
120
+ {
121
+ m_socketEventArgs . SetBuffer ( buffer . Array , buffer . Offset , buffer . Count ) ;
122
+ m_valueTaskSource . Reset ( ) ;
123
+ if ( ! m_socket . ReceiveAsync ( m_socketEventArgs ) )
124
+ PropagateSocketAsyncEventArgsStatus ( ) ;
125
+ return new ValueTask < int > ( this , m_valueTaskSource . Version ) ;
126
+ }
127
+
128
+ private ValueTask < int > WriteBytesToSocketAsync ( ArraySegment < byte > data )
129
+ {
130
+ m_socketEventArgs . SetBuffer ( data . Array , data . Offset , data . Count ) ;
131
+ m_valueTaskSource . Reset ( ) ;
132
+ if ( ! m_socket . SendAsync ( m_socketEventArgs ) )
133
+ PropagateSocketAsyncEventArgsStatus ( ) ;
134
+ return new ValueTask < int > ( this , m_valueTaskSource . Version ) ;
135
+ }
136
+ #else
137
+ private async ValueTask < int > ReadBytesFromSocketAsync ( ArraySegment < byte > buffer )
138
+ {
139
+ m_socketAwaitable . EventArgs . SetBuffer ( buffer . Array , buffer . Offset , buffer . Count ) ;
140
+ await m_socket . ReceiveAsync ( m_socketAwaitable ) ;
141
+ return m_socketAwaitable . EventArgs . BytesTransferred ;
142
+ }
143
+
144
+ private async ValueTask < int > WriteBytesToSocketAsync ( ArraySegment < byte > data )
105
145
{
106
146
m_socketAwaitable . EventArgs . SetBuffer ( data . Array , data . Offset , data . Count ) ;
107
147
await m_socket . SendAsync ( m_socketAwaitable ) ;
108
148
return 0 ;
109
149
}
150
+ #endif
151
+
152
+ #if VALUETASKSOURCE
153
+ int IValueTaskSource < int > . GetResult ( short token ) => m_valueTaskSource . GetResult ( token ) ;
154
+ ValueTaskSourceStatus IValueTaskSource < int > . GetStatus ( short token ) => m_valueTaskSource . GetStatus ( token ) ;
155
+ void IValueTaskSource < int > . OnCompleted ( Action < object ? > continuation , object ? state , short token , ValueTaskSourceOnCompletedFlags flags ) =>
156
+ m_valueTaskSource . OnCompleted ( continuation , state , token , flags ) ;
157
+
158
+ private void PropagateSocketAsyncEventArgsStatus ( )
159
+ {
160
+ if ( m_socketEventArgs . SocketError != SocketError . Success )
161
+ m_valueTaskSource . SetException ( new SocketException ( ( int ) m_socketEventArgs . SocketError ) ) ;
162
+ else
163
+ m_valueTaskSource . SetResult ( m_socketEventArgs . BytesTransferred ) ;
164
+ }
165
+ #endif
110
166
111
167
readonly Socket m_socket ;
168
+ #if VALUETASKSOURCE
169
+ ManualResetValueTaskSourceCore < int > m_valueTaskSource ; // mutable struct; do not make this readonly
170
+ readonly SocketAsyncEventArgs m_socketEventArgs ;
171
+ #else
112
172
readonly SocketAwaitable m_socketAwaitable ;
173
+ #endif
113
174
readonly Action m_closeSocket ;
114
175
}
115
176
}
0 commit comments