@@ -122,7 +122,6 @@ public Connection(IConnectionFactory factory, bool insist, IFrameHandler frameHa
122
122
StartMainLoop ( factory . UseBackgroundThreadsForIO ) ;
123
123
Open ( insist ) ;
124
124
125
- StartHeartbeatTimers ( ) ;
126
125
AppDomain . CurrentDomain . DomainUnload += HandleDomainUnload ;
127
126
}
128
127
@@ -242,10 +241,10 @@ public ushort Heartbeat
242
241
set
243
242
{
244
243
m_heartbeat = value ;
245
- // timers fire at half the interval to avoid race
244
+ // timers fire at slightly below half the interval to avoid race
246
245
// conditions
247
- m_heartbeatTimeSpan = TimeSpan . FromMilliseconds ( ( value * 1000 ) / 2.0 ) ;
248
- m_frameHandler . Timeout = ( value * 1000 ) / 2 ;
246
+ m_heartbeatTimeSpan = TimeSpan . FromMilliseconds ( ( value * 1000 ) / 4 ) ;
247
+ m_frameHandler . Timeout = value * 1000 * 2 ;
249
248
}
250
249
}
251
250
@@ -477,7 +476,7 @@ public void FinishClose()
477
476
m_heartbeatRead . Set ( ) ;
478
477
m_heartbeatWrite . Set ( ) ;
479
478
m_closed = true ;
480
- StopHeartbeatTimers ( ) ;
479
+ MaybeStopHeartbeatTimers ( ) ;
481
480
482
481
m_frameHandler . Close ( ) ;
483
482
m_model0 . SetCloseReason ( m_closeReason ) ;
@@ -896,15 +895,15 @@ public bool SetCloseReason(ShutdownEventArgs reason)
896
895
}
897
896
}
898
897
899
- public void StartHeartbeatTimers ( )
898
+ public void MaybeStartHeartbeatTimers ( )
900
899
{
901
900
if ( Heartbeat != 0 )
902
901
{
903
902
_heartbeatWriteTimer = new Timer ( HeartbeatWriteTimerCallback ) ;
904
- _heartbeatWriteTimer . Change ( TimeSpan . FromMilliseconds ( 0 ) , TimeSpan . FromMilliseconds ( - 1 ) ) ;
903
+ _heartbeatWriteTimer . Change ( TimeSpan . FromMilliseconds ( 200 ) , m_heartbeatTimeSpan ) ;
905
904
906
905
_heartbeatReadTimer = new Timer ( HeartbeatReadTimerCallback ) ;
907
- _heartbeatReadTimer . Change ( TimeSpan . FromMilliseconds ( 0 ) , TimeSpan . FromMilliseconds ( - 1 ) ) ;
906
+ _heartbeatReadTimer . Change ( TimeSpan . FromMilliseconds ( 200 ) , m_heartbeatTimeSpan ) ;
908
907
}
909
908
}
910
909
@@ -930,8 +929,11 @@ public void HeartbeatReadTimerCallback(object state)
930
929
m_missedHeartbeats = 0 ;
931
930
}
932
931
933
- // Has to miss two full heartbeats to force socket close
934
- if ( m_missedHeartbeats > 1 )
932
+ // We check against 8 = 2 * 4 because we need to wait for at
933
+ // least two complete heartbeat setting intervals before
934
+ // complaining, and we've set the socket timeout to a quarter
935
+ // of the heartbeat setting in setHeartbeat above.
936
+ if ( m_missedHeartbeats > 2 * 4 )
935
937
{
936
938
String description = String . Format ( "Heartbeat missing with heartbeat == {0} seconds" , m_heartbeat ) ;
937
939
var eose = new EndOfStreamException ( description ) ;
@@ -960,10 +962,8 @@ public void HeartbeatWriteTimerCallback(object state)
960
962
{
961
963
if ( ! m_closed )
962
964
{
963
- if ( ! m_heartbeatWrite . WaitOne ( 0 , false ) )
964
- {
965
- WriteFrame ( m_heartbeatFrame ) ;
966
- }
965
+ WriteFrame ( m_heartbeatFrame ) ;
966
+ m_frameHandler . Flush ( ) ;
967
967
}
968
968
}
969
969
catch ( Exception e )
@@ -981,13 +981,9 @@ public void HeartbeatWriteTimerCallback(object state)
981
981
TerminateMainloop ( ) ;
982
982
FinishClose ( ) ;
983
983
}
984
- else
985
- {
986
- _heartbeatWriteTimer . Change ( Heartbeat * 1000 , Timeout . Infinite ) ;
987
- }
988
984
}
989
985
990
- protected void StopHeartbeatTimers ( )
986
+ protected void MaybeStopHeartbeatTimers ( )
991
987
{
992
988
if ( _heartbeatReadTimer != null )
993
989
{
@@ -1004,7 +1000,7 @@ protected void StopHeartbeatTimers()
1004
1000
///</remarks>
1005
1001
public void TerminateMainloop ( )
1006
1002
{
1007
- StopHeartbeatTimers ( ) ;
1003
+ MaybeStopHeartbeatTimers ( ) ;
1008
1004
m_running = false ;
1009
1005
}
1010
1006
@@ -1089,7 +1085,7 @@ public void HandleConnectionUnblocked()
1089
1085
1090
1086
void IDisposable . Dispose ( )
1091
1087
{
1092
- StopHeartbeatTimers ( ) ;
1088
+ MaybeStopHeartbeatTimers ( ) ;
1093
1089
Abort ( ) ;
1094
1090
if ( ShutdownReport . Count > 0 )
1095
1091
{
@@ -1219,6 +1215,8 @@ protected void StartAndTune()
1219
1215
heartbeat ) ;
1220
1216
1221
1217
m_inConnectionNegotiation = false ;
1218
+ // now we can start heartbeat timers
1219
+ MaybeStartHeartbeatTimers ( ) ;
1222
1220
}
1223
1221
1224
1222
private static uint NegotiatedMaxValue ( uint clientValue , uint serverValue )
0 commit comments