@@ -43,11 +43,11 @@ internal sealed partial class Connection
43
43
private readonly IFrameHandler _frameHandler ;
44
44
private readonly Task _mainLoopTask ;
45
45
46
- private void MainLoop ( )
46
+ private async Task MainLoop ( )
47
47
{
48
48
try
49
49
{
50
- ReceiveLoop ( ) ;
50
+ await ReceiveLoop ( ) . ConfigureAwait ( false ) ;
51
51
}
52
52
catch ( EndOfStreamException eose )
53
53
{
@@ -56,7 +56,7 @@ private void MainLoop()
56
56
}
57
57
catch ( HardProtocolException hpe )
58
58
{
59
- HardProtocolExceptionHandler ( hpe ) ;
59
+ await HardProtocolExceptionHandler ( hpe ) . ConfigureAwait ( false ) ;
60
60
}
61
61
catch ( Exception ex )
62
62
{
@@ -66,57 +66,70 @@ private void MainLoop()
66
66
FinishClose ( ) ;
67
67
}
68
68
69
- private void ReceiveLoop ( )
69
+ private async Task ReceiveLoop ( )
70
70
{
71
71
while ( ! _closed )
72
72
{
73
- InboundFrame frame = _frameHandler . ReadFrame ( ) ;
73
+ while ( _frameHandler . TryReadFrame ( out InboundFrame frame ) )
74
+ {
75
+ NotifyHeartbeatListener ( ) ;
76
+ ProcessFrame ( frame ) ;
77
+ }
78
+
79
+ // Done reading frames synchronously, go async
80
+ InboundFrame asyncFrame = await _frameHandler . ReadFrameAsync ( )
81
+ . ConfigureAwait ( false ) ;
74
82
NotifyHeartbeatListener ( ) ;
83
+ ProcessFrame ( asyncFrame ) ;
84
+ }
85
+ }
75
86
76
- bool shallReturn = true ;
77
- if ( frame . Channel == 0 )
87
+ private void ProcessFrame ( InboundFrame frame )
88
+ {
89
+ bool shallReturnPayload = true ;
90
+ if ( frame . Channel == 0 )
91
+ {
92
+ if ( frame . Type == FrameType . FrameHeartbeat )
78
93
{
79
- if ( frame . Type == FrameType . FrameHeartbeat )
80
- {
81
- // Ignore it: we've already just reset the heartbeat
82
- }
83
- else
84
- {
85
- // In theory, we could get non-connection.close-ok
86
- // frames here while we're quiescing (m_closeReason !=
87
- // null). In practice, there's a limited number of
88
- // things the server can ask of us on channel 0 -
89
- // essentially, just connection.close. That, combined
90
- // with the restrictions on pipelining, mean that
91
- // we're OK here to handle channel 0 traffic in a
92
- // quiescing situation, even though technically we
93
- // should be ignoring everything except
94
- // connection.close-ok.
95
- shallReturn = _session0 . HandleFrame ( in frame ) ;
96
- }
94
+ // Ignore it: we've already recently reset the heartbeat
97
95
}
98
96
else
99
97
{
100
- // If we're still m_running, but have a m_closeReason,
101
- // then we must be quiescing, which means any inbound
102
- // frames for non-zero channels (and any inbound
103
- // commands on channel zero that aren't
104
- // Connection.CloseOk) must be discarded.
105
- if ( _closeReason is null )
106
- {
107
- // No close reason, not quiescing the
108
- // connection. Handle the frame. (Of course, the
109
- // Session itself may be quiescing this particular
110
- // channel, but that's none of our concern.)
111
- shallReturn = _sessionManager . Lookup ( frame . Channel ) . HandleFrame ( in frame ) ;
112
- }
98
+ // In theory, we could get non-connection.close-ok
99
+ // frames here while we're quiescing (m_closeReason !=
100
+ // null). In practice, there's a limited number of
101
+ // things the server can ask of us on channel 0 -
102
+ // essentially, just connection.close. That, combined
103
+ // with the restrictions on pipelining, mean that
104
+ // we're OK here to handle channel 0 traffic in a
105
+ // quiescing situation, even though technically we
106
+ // should be ignoring everything except
107
+ // connection.close-ok.
108
+ shallReturnPayload = _session0 . HandleFrame ( in frame ) ;
113
109
}
114
-
115
- if ( shallReturn )
110
+ }
111
+ else
112
+ {
113
+ // If we're still m_running, but have a m_closeReason,
114
+ // then we must be quiescing, which means any inbound
115
+ // frames for non-zero channels (and any inbound
116
+ // commands on channel zero that aren't
117
+ // Connection.CloseOk) must be discarded.
118
+ if ( _closeReason is null )
116
119
{
117
- frame . ReturnPayload ( ) ;
120
+ // No close reason, not quiescing the
121
+ // connection. Handle the frame. (Of course, the
122
+ // Session itself may be quiescing this particular
123
+ // channel, but that's none of our concern.)
124
+ ISession session = _sessionManager . Lookup ( frame . Channel ) ;
125
+ shallReturnPayload = session . HandleFrame ( in frame ) ;
118
126
}
119
127
}
128
+
129
+ if ( shallReturnPayload )
130
+ {
131
+ frame . ReturnPayload ( ) ;
132
+ }
120
133
}
121
134
122
135
///<remarks>
@@ -139,7 +152,7 @@ private void HandleMainLoopException(ShutdownEventArgs reason)
139
152
LogCloseError ( $ "Unexpected connection closure: { reason } ", new Exception ( reason . ToString ( ) ) ) ;
140
153
}
141
154
142
- private void HardProtocolExceptionHandler ( HardProtocolException hpe )
155
+ private async Task HardProtocolExceptionHandler ( HardProtocolException hpe )
143
156
{
144
157
if ( SetCloseReason ( hpe . ShutdownReason ) )
145
158
{
@@ -151,7 +164,8 @@ private void HardProtocolExceptionHandler(HardProtocolException hpe)
151
164
_session0 . Transmit ( in cmd ) ;
152
165
if ( hpe . CanShutdownCleanly )
153
166
{
154
- ClosingLoop ( ) ;
167
+ await ClosingLoop ( )
168
+ . ConfigureAwait ( false ) ;
155
169
}
156
170
}
157
171
catch ( IOException ioe )
@@ -168,13 +182,14 @@ private void HardProtocolExceptionHandler(HardProtocolException hpe)
168
182
///<remarks>
169
183
/// Loop only used while quiescing. Use only to cleanly close connection
170
184
///</remarks>
171
- private void ClosingLoop ( )
185
+ private async Task ClosingLoop ( )
172
186
{
173
187
try
174
188
{
175
189
_frameHandler . ReadTimeout = TimeSpan . Zero ;
176
190
// Wait for response/socket closure or timeout
177
- ReceiveLoop ( ) ;
191
+ await ReceiveLoop ( )
192
+ . ConfigureAwait ( false ) ;
178
193
}
179
194
catch ( ObjectDisposedException ode )
180
195
{
0 commit comments