@@ -1012,6 +1012,8 @@ public void MaybeStartHeartbeatTimers()
1012
1012
{
1013
1013
if ( Heartbeat != 0 )
1014
1014
{
1015
+ IsDisposedHeartBeatReadTimer = false ;
1016
+ IsDisposedHeartBeatWriteTimer = false ;
1015
1017
#if NETFX_CORE
1016
1018
_heartbeatWriteTimer = new Timer ( HeartbeatWriteTimerCallback ) ;
1017
1019
_heartbeatReadTimer = new Timer ( HeartbeatReadTimerCallback ) ;
@@ -1040,99 +1042,127 @@ public void StartMainLoop(bool useBackgroundThread)
1040
1042
#endif
1041
1043
}
1042
1044
1045
+ private readonly object heartBeatReadLock = new object ( ) ;
1046
+ private readonly object heartBeatWriteLock = new object ( ) ;
1047
+ public bool IsDisposedHeartBeatReadTimer { get ; set ; }
1048
+ public bool IsDisposedHeartBeatWriteTimer { get ; set ; }
1049
+
1043
1050
public void HeartbeatReadTimerCallback ( object state )
1044
1051
{
1045
- bool shouldTerminate = false ;
1046
- try
1052
+ lock ( heartBeatReadLock )
1047
1053
{
1048
- if ( ! m_closed )
1054
+ if ( IsDisposedHeartBeatReadTimer )
1055
+ {
1056
+ return ;
1057
+ }
1058
+ bool shouldTerminate = false ;
1059
+ try
1049
1060
{
1050
- if ( ! m_heartbeatRead . WaitOne ( 0 ) )
1061
+ if ( ! m_closed )
1051
1062
{
1052
- m_missedHeartbeats ++ ;
1063
+ if ( ! m_heartbeatRead . WaitOne ( 0 ) )
1064
+ {
1065
+ m_missedHeartbeats ++ ;
1066
+ }
1067
+ else
1068
+ {
1069
+ m_missedHeartbeats = 0 ;
1070
+ }
1071
+
1072
+ // We check against 8 = 2 * 4 because we need to wait for at
1073
+ // least two complete heartbeat setting intervals before
1074
+ // complaining, and we've set the socket timeout to a quarter
1075
+ // of the heartbeat setting in setHeartbeat above.
1076
+ if ( m_missedHeartbeats > 2 * 4 )
1077
+ {
1078
+ String description = String . Format ( "Heartbeat missing with heartbeat == {0} seconds" , m_heartbeat ) ;
1079
+ var eose = new EndOfStreamException ( description ) ;
1080
+ ESLog . Error ( description , eose ) ;
1081
+ m_shutdownReport . Add ( new ShutdownReportEntry ( description , eose ) ) ;
1082
+ HandleMainLoopException (
1083
+ new ShutdownEventArgs ( ShutdownInitiator . Library , 0 , "End of stream" , eose ) ) ;
1084
+ shouldTerminate = true ;
1085
+ }
1053
1086
}
1054
- else
1087
+
1088
+ if ( shouldTerminate )
1055
1089
{
1056
- m_missedHeartbeats = 0 ;
1090
+ TerminateMainloop ( ) ;
1091
+ FinishClose ( ) ;
1057
1092
}
1058
-
1059
- // We check against 8 = 2 * 4 because we need to wait for at
1060
- // least two complete heartbeat setting intervals before
1061
- // complaining, and we've set the socket timeout to a quarter
1062
- // of the heartbeat setting in setHeartbeat above.
1063
- if ( m_missedHeartbeats > 2 * 4 )
1093
+ else if ( _heartbeatReadTimer != null )
1064
1094
{
1065
- String description = String . Format ( "Heartbeat missing with heartbeat == {0} seconds" , m_heartbeat ) ;
1066
- var eose = new EndOfStreamException ( description ) ;
1067
- ESLog . Error ( description , eose ) ;
1068
- m_shutdownReport . Add ( new ShutdownReportEntry ( description , eose ) ) ;
1069
- HandleMainLoopException (
1070
- new ShutdownEventArgs ( ShutdownInitiator . Library , 0 , "End of stream" , eose ) ) ;
1071
- shouldTerminate = true ;
1095
+ _heartbeatReadTimer . Change ( Heartbeat * 1000 , Timeout . Infinite ) ;
1072
1096
}
1073
1097
}
1074
-
1075
- if ( shouldTerminate )
1098
+ catch ( ObjectDisposedException )
1076
1099
{
1077
- TerminateMainloop ( ) ;
1078
- FinishClose ( ) ;
1100
+ // timer is already disposed,
1101
+ // e.g. due to shutdown
1079
1102
}
1080
- else if ( _heartbeatReadTimer != null )
1103
+ catch ( NullReferenceException )
1081
1104
{
1082
- _heartbeatReadTimer . Change ( Heartbeat * 1000 , Timeout . Infinite ) ;
1105
+ // timer has already been disposed from a different thread after null check
1106
+ // this event should be rare
1083
1107
}
1084
1108
}
1085
- catch ( ObjectDisposedException )
1086
- {
1087
- // timer is already disposed,
1088
- // e.g. due to shutdown
1089
- }
1090
- catch ( NullReferenceException )
1091
- {
1092
- // timer has already been disposed from a different thread after null check
1093
- // this event should be rare
1094
- }
1095
1109
}
1096
1110
1097
1111
public void HeartbeatWriteTimerCallback ( object state )
1098
1112
{
1099
- bool shouldTerminate = false ;
1100
- try
1113
+ lock ( heartBeatWriteLock )
1101
1114
{
1115
+ if ( IsDisposedHeartBeatWriteTimer )
1116
+ {
1117
+ return ;
1118
+ }
1119
+ bool shouldTerminate = false ;
1102
1120
try
1103
1121
{
1104
- if ( ! m_closed )
1122
+ try
1105
1123
{
1106
- WriteFrame ( m_heartbeatFrame ) ;
1124
+ if ( ! m_closed )
1125
+ {
1126
+ WriteFrame ( m_heartbeatFrame ) ;
1127
+ }
1128
+ }
1129
+ catch ( Exception e )
1130
+ {
1131
+ HandleMainLoopException ( new ShutdownEventArgs (
1132
+ ShutdownInitiator . Library ,
1133
+ 0 ,
1134
+ "End of stream" ,
1135
+ e ) ) ;
1136
+ shouldTerminate = true ;
1107
1137
}
1108
- }
1109
- catch ( Exception e )
1110
- {
1111
- HandleMainLoopException ( new ShutdownEventArgs (
1112
- ShutdownInitiator . Library ,
1113
- 0 ,
1114
- "End of stream" ,
1115
- e ) ) ;
1116
- shouldTerminate = true ;
1117
- }
1118
1138
1119
- if ( m_closed || shouldTerminate )
1120
- {
1121
- TerminateMainloop ( ) ;
1122
- FinishClose ( ) ;
1139
+ if ( m_closed || shouldTerminate )
1140
+ {
1141
+ TerminateMainloop ( ) ;
1142
+ FinishClose ( ) ;
1143
+ }
1123
1144
}
1124
- }
1125
- catch ( ObjectDisposedException )
1126
- {
1127
- // timer is already disposed,
1128
- // e.g. due to shutdown
1145
+ catch ( ObjectDisposedException )
1146
+ {
1147
+ // timer is already disposed,
1148
+ // e.g. due to shutdown
1149
+ } /**/
1129
1150
}
1130
1151
}
1131
1152
1132
1153
protected void MaybeStopHeartbeatTimers ( )
1133
1154
{
1134
- MaybeDisposeTimer ( ref _heartbeatReadTimer ) ;
1135
- MaybeDisposeTimer ( ref _heartbeatWriteTimer ) ;
1155
+ lock ( heartBeatReadLock )
1156
+ {
1157
+ MaybeDisposeTimer ( ref _heartbeatReadTimer ) ;
1158
+ IsDisposedHeartBeatReadTimer = true ;
1159
+ }
1160
+
1161
+ lock ( heartBeatWriteLock )
1162
+ {
1163
+ MaybeDisposeTimer ( ref _heartbeatWriteTimer ) ;
1164
+ IsDisposedHeartBeatWriteTimer = true ;
1165
+ }
1136
1166
}
1137
1167
1138
1168
private void MaybeDisposeTimer ( ref Timer timer )
0 commit comments