From b99de67b5d6049b156d96f7d8f86de647b2e49c6 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Wed, 27 Dec 2017 00:47:11 +0000 Subject: [PATCH 1/2] Don't capture AsyncLocals into HttpConnectionPools timer --- .../src/System/Net/Http/Managed/HttpConnectionPools.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionPools.cs b/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionPools.cs index 2650b7bab385..441e957672dc 100644 --- a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionPools.cs +++ b/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionPools.cs @@ -39,7 +39,12 @@ public HttpConnectionPools(int maxConnectionsPerServer) _maxConnectionsPerServer = maxConnectionsPerServer; _pools = new ConcurrentDictionary(); // Start out with the timer not running, since we have no pools. + + // Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever + ExecutionContext.SuppressFlow(); _cleaningTimer = new Timer(s => ((HttpConnectionPools)s).RemoveStalePools(), this, Timeout.Infinite, Timeout.Infinite); + // Restore the current ExecutionContext + ExecutionContext.RestoreFlow(); } /// Gets a pool for the specified endpoint, adding one if none existed. From 561c1a695ce90eb6ede6d0a4af179124b53db314 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Wed, 27 Dec 2017 21:02:36 +0000 Subject: [PATCH 2/2] Harden EC flow suppression --- .../Net/Http/Managed/HttpConnectionPools.cs | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionPools.cs b/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionPools.cs index 441e957672dc..d1d043b5432b 100644 --- a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionPools.cs +++ b/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionPools.cs @@ -41,10 +41,23 @@ public HttpConnectionPools(int maxConnectionsPerServer) // Start out with the timer not running, since we have no pools. // Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever - ExecutionContext.SuppressFlow(); - _cleaningTimer = new Timer(s => ((HttpConnectionPools)s).RemoveStalePools(), this, Timeout.Infinite, Timeout.Infinite); - // Restore the current ExecutionContext - ExecutionContext.RestoreFlow(); + bool restoreFlow = false; + try + { + if (!ExecutionContext.IsFlowSuppressed()) + { + ExecutionContext.SuppressFlow(); + restoreFlow = true; + } + + _cleaningTimer = new Timer(s => ((HttpConnectionPools)s).RemoveStalePools(), this, Timeout.Infinite, Timeout.Infinite); + } + finally + { + // Restore the current ExecutionContext + if (restoreFlow) + ExecutionContext.RestoreFlow(); + } } /// Gets a pool for the specified endpoint, adding one if none existed.