diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 781ab610399e..15af9c2cace7 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,16 +1,16 @@ - + https://github.com/dotnet/coreclr - 42d8e40e469cf00128e0cfa48f24297afa13c36f + fa8383fb28be945cae900a5579afd5920f274fd4 - + https://github.com/dotnet/coreclr - 42d8e40e469cf00128e0cfa48f24297afa13c36f + fa8383fb28be945cae900a5579afd5920f274fd4 - + https://github.com/dotnet/coreclr - 42d8e40e469cf00128e0cfa48f24297afa13c36f + fa8383fb28be945cae900a5579afd5920f274fd4 diff --git a/eng/Versions.props b/eng/Versions.props index 72ee1ed3b4be..a1326d3cb153 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -40,8 +40,8 @@ 3.0.0-preview6-27729-07 3.0.0-preview6-27729-07 - 3.0.0-preview6.19279.4 - 3.0.0-preview6.19279.4 + 3.0.0-preview6.19280.2 + 3.0.0-preview6.19280.2 3.0.0-preview6.19279.8 4.6.0-preview6.19279.8 diff --git a/global.json b/global.json index a30fe7ce1126..1a2b617d4a01 100644 --- a/global.json +++ b/global.json @@ -6,6 +6,6 @@ "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19279.5", "Microsoft.DotNet.Helix.Sdk": "2.0.0-beta.19279.5", "FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", - "Microsoft.NET.Sdk.IL": "3.0.0-preview6.19279.4" + "Microsoft.NET.Sdk.IL": "3.0.0-preview6.19280.2" } } diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinInetProxyHelper.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinInetProxyHelper.cs index a56bea19c77d..4a26aa83a69d 100644 --- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinInetProxyHelper.cs +++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinInetProxyHelper.cs @@ -179,4 +179,4 @@ public bool GetProxyForUrl( return useProxy; } } -} +} \ No newline at end of file diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs index b85233f76308..8b7b95bba16e 100644 --- a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs +++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs @@ -41,7 +41,7 @@ internal sealed partial class Http2Connection : HttpConnectionBase, IDisposable private int _initialWindowSize; private int _maxConcurrentStreams; private int _pendingWindowUpdate; - private int _idleSinceTickCount; + private long _idleSinceTickCount; private int _pendingWriters; private bool _disposed; @@ -1138,7 +1138,7 @@ private void Abort(Exception abortException) } /// Gets whether the connection exceeded any of the connection limits. - /// The current tick count. Passed in to amortize the cost of calling Environment.TickCount. + /// The current tick count. Passed in to amortize the cost of calling Environment.TickCount64. /// How long a connection can be open to be considered reusable. /// How long a connection can have been idle in the pool to be considered reusable. /// @@ -1149,7 +1149,7 @@ private void Abort(Exception abortException) /// the nature of connection pooling. /// - public bool IsExpired(int nowTicks, + public bool IsExpired(long nowTicks, TimeSpan connectionLifetime, TimeSpan connectionIdleTimeout) @@ -1162,9 +1162,9 @@ public bool IsExpired(int nowTicks, // Check idle timeout when there are not pending requests for a while. if ((connectionIdleTimeout != Timeout.InfiniteTimeSpan) && (_httpStreams.Count == 0) && - ((uint)(nowTicks - _idleSinceTickCount) > connectionIdleTimeout.TotalMilliseconds)) + ((nowTicks - _idleSinceTickCount) > connectionIdleTimeout.TotalMilliseconds)) { - if (NetEventSource.IsEnabled) Trace($"Connection no longer usable. Idle {TimeSpan.FromMilliseconds((uint)(nowTicks - _idleSinceTickCount))} > {connectionIdleTimeout}."); + if (NetEventSource.IsEnabled) Trace($"Connection no longer usable. Idle {TimeSpan.FromMilliseconds((nowTicks - _idleSinceTickCount))} > {connectionIdleTimeout}."); return true; } @@ -1448,7 +1448,7 @@ private void RemoveStream(Http2Stream http2Stream) if (_httpStreams.Count == 0) { // If this was last pending request, get timestamp so we can monitor idle time. - _idleSinceTickCount = Environment.TickCount; + _idleSinceTickCount = Environment.TickCount64; } if (_disposed) diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs index 2e6d4320d1f8..24deb84eb07d 100644 --- a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs +++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs @@ -12,16 +12,16 @@ internal abstract class HttpConnectionBase public abstract Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken); internal abstract void Trace(string message, string memberName = null); - private int CreationTickCount { get; } = Environment.TickCount; + private long CreationTickCount { get; } = Environment.TickCount64; // Check if lifetime expired on connection. - public bool LifetimeExpired(int nowTicks, TimeSpan lifetime) + public bool LifetimeExpired(long nowTicks, TimeSpan lifetime) { bool expired = lifetime != Timeout.InfiniteTimeSpan && - (lifetime == TimeSpan.Zero || (uint)(nowTicks - CreationTickCount) > lifetime.TotalMilliseconds); + (lifetime == TimeSpan.Zero || (nowTicks - CreationTickCount) > lifetime.TotalMilliseconds); - if (expired && NetEventSource.IsEnabled) Trace($"Connection no longer usable. Alive {TimeSpan.FromMilliseconds((uint)(nowTicks - CreationTickCount))} > {lifetime}."); + if (expired && NetEventSource.IsEnabled) Trace($"Connection no longer usable. Alive {TimeSpan.FromMilliseconds((nowTicks - CreationTickCount))} > {lifetime}."); return expired; } } diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs index ba6050598202..624de5c3e2ec 100644 --- a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs +++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs @@ -229,7 +229,7 @@ private ValueTask GetOrReserveHttp11ConnectionAsync(Cancellation TimeSpan pooledConnectionLifetime = _poolManager.Settings._pooledConnectionLifetime; TimeSpan pooledConnectionIdleTimeout = _poolManager.Settings._pooledConnectionIdleTimeout; - int nowTicks = Environment.TickCount; + long nowTicks = Environment.TickCount64; List list = _idleConnections; // Try to find a usable cached connection. @@ -340,7 +340,7 @@ private ValueTask GetOrReserveHttp11ConnectionAsync(Cancellation if (http2Connection != null) { TimeSpan pooledConnectionLifetime = _poolManager.Settings._pooledConnectionLifetime; - if (http2Connection.LifetimeExpired(Environment.TickCount, pooledConnectionLifetime)) + if (http2Connection.LifetimeExpired(Environment.TickCount64, pooledConnectionLifetime)) { // Connection expired. http2Connection.Dispose(); @@ -797,7 +797,7 @@ public void DecrementConnectionCount() /// The connection to return. public void ReturnConnection(HttpConnection connection) { - bool lifetimeExpired = connection.LifetimeExpired(Environment.TickCount, _poolManager.Settings._pooledConnectionLifetime); + bool lifetimeExpired = connection.LifetimeExpired(Environment.TickCount64, _poolManager.Settings._pooledConnectionLifetime); if (!lifetimeExpired) { @@ -915,7 +915,7 @@ public bool CleanCacheAndDisposeIfUnused() // Get the current time. This is compared against each connection's last returned // time to determine whether a connection is too old and should be closed. - int nowTicks = Environment.TickCount; + long nowTicks = Environment.TickCount64; Http2Connection http2Connection = _http2Connection; if (http2Connection != null) @@ -1039,7 +1039,7 @@ private void Trace(string message, [CallerMemberName] string memberName = null) /// The cached connection. internal readonly HttpConnection _connection; /// The last tick count at which the connection was used. - internal readonly int _returnedTickCount; + internal readonly long _returnedTickCount; /// Initializes the cached connection and its associated metadata. /// The connection. @@ -1047,7 +1047,7 @@ public CachedConnection(HttpConnection connection) { Debug.Assert(connection != null); _connection = connection; - _returnedTickCount = Environment.TickCount; + _returnedTickCount = Environment.TickCount64; } /// Gets whether the connection is currently usable. @@ -1062,16 +1062,16 @@ public CachedConnection(HttpConnection connection) /// the nature of connection pooling. /// public bool IsUsable( - int nowTicks, + long nowTicks, TimeSpan pooledConnectionLifetime, TimeSpan pooledConnectionIdleTimeout, bool poll = false) { // Validate that the connection hasn't been idle in the pool for longer than is allowed. if ((pooledConnectionIdleTimeout != Timeout.InfiniteTimeSpan) && - ((uint)(nowTicks - _returnedTickCount) > pooledConnectionIdleTimeout.TotalMilliseconds)) + ((nowTicks - _returnedTickCount) > pooledConnectionIdleTimeout.TotalMilliseconds)) { - if (NetEventSource.IsEnabled) _connection.Trace($"Connection no longer usable. Idle {TimeSpan.FromMilliseconds((uint)(nowTicks - _returnedTickCount))} > {pooledConnectionIdleTimeout}."); + if (NetEventSource.IsEnabled) _connection.Trace($"Connection no longer usable. Idle {TimeSpan.FromMilliseconds((nowTicks - _returnedTickCount))} > {pooledConnectionIdleTimeout}."); return false; } diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionSettings.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionSettings.cs index 3fe40764bce8..f6788731ce8c 100644 --- a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionSettings.cs +++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionSettings.cs @@ -64,17 +64,6 @@ public HttpConnectionSettings CloneAndNormalize() _cookieContainer = new CookieContainer(); } - // The implementation uses Environment.TickCount to track connection lifetimes, as Environment.TickCount - // is measurable faster than DateTime.UtcNow / Stopwatch.GetTimestamp, and we do it at least once per request. - // However, besides its lower resolution (which is fine for SocketHttpHandler's needs), due to being based on - // an Int32 rather than Int64, the difference between two tick counts is at most ~49 days. This means that - // specifying a connection idle or lifetime of greater than 49 days would cause it to never be reached. The - // chances of a connection being open anywhere near that long is close to zero, as is the chance that someone - // would choose to specify such a long timeout, but regardless, we avoid issues by capping the timeouts. - TimeSpan timeLimit = TimeSpan.FromDays(40); // something super long but significantly less than the 49 day limit - TimeSpan pooledConnectionLifetime = _pooledConnectionLifetime < timeLimit ? _pooledConnectionLifetime : timeLimit; - TimeSpan pooledConnectionIdleTimeout = _pooledConnectionIdleTimeout < timeLimit ? _pooledConnectionIdleTimeout : timeLimit; - return new HttpConnectionSettings() { _allowAutoRedirect = _allowAutoRedirect, @@ -90,8 +79,8 @@ public HttpConnectionSettings CloneAndNormalize() _maxResponseDrainSize = _maxResponseDrainSize, _maxResponseDrainTime = _maxResponseDrainTime, _maxResponseHeadersLength = _maxResponseHeadersLength, - _pooledConnectionLifetime = pooledConnectionLifetime, - _pooledConnectionIdleTimeout = pooledConnectionIdleTimeout, + _pooledConnectionLifetime = _pooledConnectionLifetime, + _pooledConnectionIdleTimeout = _pooledConnectionIdleTimeout, _preAuthenticate = _preAuthenticate, _properties = _properties, _proxy = _proxy, diff --git a/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.cs b/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.cs index ca2b6f40e46e..7688ffebe9b0 100644 --- a/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.cs +++ b/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.cs @@ -670,6 +670,7 @@ public static partial class Environment public static string SystemDirectory { get { throw null; } } public static int SystemPageSize { get { throw null; } } public static int TickCount { get { throw null; } } + public static long TickCount64 { get { throw null; } } public static string UserDomainName { get { throw null; } } public static bool UserInteractive { get { throw null; } } public static string UserName { get { throw null; } } diff --git a/src/System.Runtime.Extensions/tests/System/Environment.TickCount.cs b/src/System.Runtime.Extensions/tests/System/Environment.TickCount.cs index ccd28e9999fc..b2e8f3794f5c 100644 --- a/src/System.Runtime.Extensions/tests/System/Environment.TickCount.cs +++ b/src/System.Runtime.Extensions/tests/System/Environment.TickCount.cs @@ -15,7 +15,7 @@ public class EnvironmentTickCount public void TickCountTest() { int start = Environment.TickCount; - HashSet times = new HashSet(); + var times = new HashSet(); Func test = () => { int time = Environment.TickCount; @@ -26,5 +26,21 @@ public void TickCountTest() SpinWait.SpinUntil(test, TimeSpan.FromSeconds(1)) || test(), $"TickCount did not increase after one second. start: {start}, values tested: {string.Join(", ", times.ToArray())}."); } + + [Fact] + public void TickCount64Test() + { + long start = Environment.TickCount64; + var times = new HashSet(); + Func test = () => + { + long time = Environment.TickCount64; + times.Add(time); + return time - start > 0; + }; + Assert.True( + SpinWait.SpinUntil(test, TimeSpan.FromSeconds(1)) || test(), + $"TickCount did not increase after one second. start: {start}, values tested: {string.Join(", ", times.ToArray())}."); + } } }