1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 // 6 // Class used to manage timeouts in complex system operations. 7 // 8 9 using System.Data.Common; 10 using System.Diagnostics; 11 12 namespace System.Data.ProviderBase 13 { 14 // Purpose: 15 // Manages determining and tracking timeouts 16 // 17 // Intended use: 18 // Call StartXXXXTimeout() to get a timer with the given expiration point 19 // Get remaining time in appropriate format to pass to subsystem timeouts 20 // Check for timeout via IsExpired for checks in managed code. 21 // Simply abandon to GC when done. 22 internal class TimeoutTimer 23 { 24 //------------------- 25 // Fields 26 //------------------- 27 private long _timerExpire; 28 private bool _isInfiniteTimeout; 29 30 //------------------- 31 // Timeout-setting methods 32 //------------------- 33 34 // Get a new timer that will expire in the given number of seconds 35 // For input, a value of zero seconds indicates infinite timeout StartSecondsTimeout(int seconds)36 internal static TimeoutTimer StartSecondsTimeout(int seconds) 37 { 38 //-------------------- 39 // Preconditions: None (seconds must conform to SetTimeoutSeconds requirements) 40 41 //-------------------- 42 // Method body 43 var timeout = new TimeoutTimer(); 44 timeout.SetTimeoutSeconds(seconds); 45 46 //--------------------- 47 // Postconditions 48 Debug.Assert(timeout != null); // Need a valid timeouttimer if no error 49 50 return timeout; 51 } 52 53 // Get a new timer that will expire in the given number of milliseconds 54 // No current need to support infinite milliseconds timeout StartMillisecondsTimeout(long milliseconds)55 internal static TimeoutTimer StartMillisecondsTimeout(long milliseconds) 56 { 57 //-------------------- 58 // Preconditions 59 Debug.Assert(0 <= milliseconds); 60 61 //-------------------- 62 // Method body 63 var timeout = new TimeoutTimer(); 64 timeout._timerExpire = checked(ADP.TimerCurrent() + (milliseconds * TimeSpan.TicksPerMillisecond)); 65 timeout._isInfiniteTimeout = false; 66 67 //--------------------- 68 // Postconditions 69 Debug.Assert(timeout != null); // Need a valid timeouttimer if no error 70 71 return timeout; 72 } 73 74 //------------------- 75 // Methods for changing timeout 76 //------------------- 77 SetTimeoutSeconds(int seconds)78 internal void SetTimeoutSeconds(int seconds) 79 { 80 //-------------------- 81 // Preconditions 82 Debug.Assert(0 <= seconds || InfiniteTimeout == seconds); // no need to support negative seconds at present 83 84 //-------------------- 85 // Method body 86 if (InfiniteTimeout == seconds) 87 { 88 _isInfiniteTimeout = true; 89 } 90 else 91 { 92 // Stash current time + timeout 93 _timerExpire = checked(ADP.TimerCurrent() + ADP.TimerFromSeconds(seconds)); 94 _isInfiniteTimeout = false; 95 } 96 //--------------------- 97 // Postconditions:None 98 } 99 100 //------------------- 101 // Timeout info properties 102 //------------------- 103 104 // Indicator for infinite timeout when starting a timer 105 internal static readonly long InfiniteTimeout = 0; 106 107 // Is this timer in an expired state? 108 internal bool IsExpired 109 { 110 get 111 { 112 return !IsInfinite && ADP.TimerHasExpired(_timerExpire); 113 } 114 } 115 116 // is this an infinite-timeout timer? 117 internal bool IsInfinite 118 { 119 get 120 { 121 return _isInfiniteTimeout; 122 } 123 } 124 125 // Special accessor for TimerExpire for use when thunking to legacy timeout methods. 126 internal long LegacyTimerExpire 127 { 128 get 129 { 130 return (_isInfiniteTimeout) ? Int64.MaxValue : _timerExpire; 131 } 132 } 133 134 // Returns milliseconds remaining trimmed to zero for none remaining 135 // and long.MaxValue for infinite 136 // This method should be preferred for internal calculations that are not 137 // yet common enough to code into the TimeoutTimer class itself. 138 internal long MillisecondsRemaining 139 { 140 get 141 { 142 //------------------- 143 // Preconditions: None 144 145 //------------------- 146 // Method Body 147 long milliseconds; 148 if (_isInfiniteTimeout) 149 { 150 milliseconds = long.MaxValue; 151 } 152 else 153 { 154 milliseconds = ADP.TimerRemainingMilliseconds(_timerExpire); 155 if (0 > milliseconds) 156 { 157 milliseconds = 0; 158 } 159 } 160 161 //-------------------- 162 // Postconditions 163 Debug.Assert(0 <= milliseconds); // This property guarantees no negative return values 164 165 return milliseconds; 166 } 167 } 168 } 169 } 170 171