@@ -11,11 +11,14 @@ internal sealed class TimeoutControl : ITimeoutControl, IConnectionTimeoutFeatur
1111{
1212 private readonly ITimeoutHandler _timeoutHandler ;
1313
14+ private readonly long _heartbeatIntervalTicks ;
15+ private readonly long _tickFrequency ;
1416 private long _lastTimestamp ;
1517 private long _timeoutTimestamp = long . MaxValue ;
1618
1719 private readonly object _readTimingLock = new object ( ) ;
1820 private MinDataRate ? _minReadRate ;
21+ private long _minReadRateGracePeriodTicks ;
1922 private bool _readTimingEnabled ;
2023 private bool _readTimingPauseRequested ;
2124 private long _readTimingElapsedTicks ;
@@ -29,9 +32,11 @@ internal sealed class TimeoutControl : ITimeoutControl, IConnectionTimeoutFeatur
2932 private int _concurrentAwaitingWrites ;
3033 private long _writeTimingTimeoutTimestamp ;
3134
32- public TimeoutControl ( ITimeoutHandler timeoutHandler )
35+ public TimeoutControl ( ITimeoutHandler timeoutHandler , long tickFrequency )
3336 {
3437 _timeoutHandler = timeoutHandler ;
38+ _tickFrequency = tickFrequency ;
39+ _heartbeatIntervalTicks = Heartbeat . Interval . ToTicks ( _tickFrequency ) ;
3540 }
3641
3742 public TimeoutReason TimerReason { get ; private set ; }
@@ -43,9 +48,9 @@ internal void Initialize(long nowTicks)
4348 _lastTimestamp = nowTicks ;
4449 }
4550
46- public void Tick ( DateTimeOffset now )
51+ public void Tick ( long now )
4752 {
48- var timestamp = now . Ticks ;
53+ var timestamp = now ;
4954
5055 CheckForTimeout ( timestamp ) ;
5156 CheckForReadDataRateTimeout ( timestamp ) ;
@@ -108,13 +113,13 @@ private void CheckForReadDataRateTimeout(long timestamp)
108113
109114 // Assume overly long tick intervals are the result of server resource starvation.
110115 // Don't count extra time between ticks against the rate limit.
111- _readTimingElapsedTicks += Math . Min ( timestamp - _lastTimestamp , Heartbeat . Interval . Ticks ) ;
116+ _readTimingElapsedTicks += Math . Min ( timestamp - _lastTimestamp , _heartbeatIntervalTicks ) ;
112117
113118 Debug . Assert ( _minReadRate != null ) ;
114119
115- if ( _minReadRate . BytesPerSecond > 0 && _readTimingElapsedTicks > _minReadRate . GracePeriod . Ticks )
120+ if ( _minReadRate . BytesPerSecond > 0 && _readTimingElapsedTicks > _minReadRateGracePeriodTicks )
116121 {
117- var elapsedSeconds = ( double ) _readTimingElapsedTicks / TimeSpan . TicksPerSecond ;
122+ var elapsedSeconds = ( double ) _readTimingElapsedTicks / _tickFrequency ;
118123 var rate = _readTimingBytesRead / elapsedSeconds ;
119124
120125 timeout = rate < _minReadRate . BytesPerSecond && ! Debugger . IsAttached ;
@@ -145,7 +150,7 @@ private void CheckForWriteDataRateTimeout(long timestamp)
145150 {
146151 // Assume overly long tick intervals are the result of server resource starvation.
147152 // Don't count extra time between ticks against the rate limit.
148- var extraTimeForTick = timestamp - _lastTimestamp - Heartbeat . Interval . Ticks ;
153+ var extraTimeForTick = timestamp - _lastTimestamp - _heartbeatIntervalTicks ;
149154
150155 if ( extraTimeForTick > 0 )
151156 {
@@ -186,7 +191,7 @@ private void AssignTimeout(long ticks, TimeoutReason timeoutReason)
186191 TimerReason = timeoutReason ;
187192
188193 // Add Heartbeat.Interval since this can be called right before the next heartbeat.
189- Interlocked . Exchange ( ref _timeoutTimestamp , Interlocked . Read ( ref _lastTimestamp ) + ticks + Heartbeat . Interval . Ticks ) ;
194+ Interlocked . Exchange ( ref _timeoutTimestamp , Interlocked . Read ( ref _lastTimestamp ) + ticks + _heartbeatIntervalTicks ) ;
190195 }
191196
192197 public void InitializeHttp2 ( InputFlowControl connectionInputFlowControl )
@@ -202,6 +207,7 @@ public void StartRequestBody(MinDataRate minRate)
202207 Debug . Assert ( _concurrentIncompleteRequestBodies == 0 || minRate == _minReadRate , "Multiple simultaneous read data rates are not supported." ) ;
203208
204209 _minReadRate = minRate ;
210+ _minReadRateGracePeriodTicks = minRate . GracePeriod . ToTicks ( _tickFrequency ) ;
205211 _concurrentIncompleteRequestBodies ++ ;
206212
207213 if ( _concurrentIncompleteRequestBodies == 1 )
@@ -282,14 +288,14 @@ public void BytesWrittenToBuffer(MinDataRate minRate, long count)
282288 lock ( _writeTimingLock )
283289 {
284290 // Add Heartbeat.Interval since this can be called right before the next heartbeat.
285- var currentTimeUpperBound = Interlocked . Read ( ref _lastTimestamp ) + Heartbeat . Interval . Ticks ;
286- var ticksToCompleteWriteAtMinRate = TimeSpan . FromSeconds ( count / minRate . BytesPerSecond ) . Ticks ;
291+ var currentTimeUpperBound = Interlocked . Read ( ref _lastTimestamp ) + _heartbeatIntervalTicks ;
292+ var ticksToCompleteWriteAtMinRate = TimeSpan . FromSeconds ( count / minRate . BytesPerSecond ) . ToTicks ( _tickFrequency ) ;
287293
288294 // If ticksToCompleteWriteAtMinRate is less than the configured grace period,
289295 // allow that write to take up to the grace period to complete. Only add the grace period
290296 // to the current time and not to any accumulated timeout.
291297 var singleWriteTimeoutTimestamp = currentTimeUpperBound + Math . Max (
292- minRate . GracePeriod . Ticks ,
298+ minRate . GracePeriod . ToTicks ( _tickFrequency ) ,
293299 ticksToCompleteWriteAtMinRate ) ;
294300
295301 // Don't penalize a connection for completing previous writes more quickly than required.
@@ -316,7 +322,7 @@ void IConnectionTimeoutFeature.SetTimeout(TimeSpan timeSpan)
316322 throw new InvalidOperationException ( CoreStrings . ConcurrentTimeoutsNotSupported ) ;
317323 }
318324
319- SetTimeout ( timeSpan . Ticks , TimeoutReason . TimeoutFeature ) ;
325+ SetTimeout ( timeSpan . ToTicks ( _tickFrequency ) , TimeoutReason . TimeoutFeature ) ;
320326 }
321327
322328 void IConnectionTimeoutFeature . ResetTimeout ( TimeSpan timeSpan )
@@ -326,13 +332,13 @@ void IConnectionTimeoutFeature.ResetTimeout(TimeSpan timeSpan)
326332 throw new ArgumentException ( CoreStrings . PositiveFiniteTimeSpanRequired , nameof ( timeSpan ) ) ;
327333 }
328334
329- ResetTimeout ( timeSpan . Ticks , TimeoutReason . TimeoutFeature ) ;
335+ ResetTimeout ( timeSpan . ToTicks ( _tickFrequency ) , TimeoutReason . TimeoutFeature ) ;
330336 }
331337
332338 public long GetResponseDrainDeadline ( long ticks , MinDataRate minRate )
333339 {
334340 // On grace period overflow, use max value.
335- var gracePeriod = ticks + minRate . GracePeriod . Ticks ;
341+ var gracePeriod = ticks + minRate . GracePeriod . ToTicks ( _tickFrequency ) ;
336342 gracePeriod = gracePeriod >= 0 ? gracePeriod : long . MaxValue ;
337343
338344 return Math . Max ( _writeTimingTimeoutTimestamp , gracePeriod ) ;
0 commit comments