Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Harden ExecutionContext SuppressFlow
Browse files Browse the repository at this point in the history
  • Loading branch information
benaadams committed Dec 27, 2017
1 parent e20cb38 commit afba626
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,27 @@ virtual internal DbConnectionPoolGroupProviderInfo CreateConnectionPoolGroupProv

private Timer CreatePruningTimer()
{
Timer timer;
// Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever
ExecutionContext.SuppressFlow();
TimerCallback callback = new TimerCallback(PruneConnectionPoolGroups);
Timer timer = new Timer(callback, null, PruningDueTime, PruningPeriod);
// Restore the current ExecutionContext
ExecutionContext.RestoreFlow();
bool restoreFlow = false;
try
{
if (!ExecutionContext.IsFlowSuppressed())
{
ExecutionContext.SuppressFlow();
restoreFlow = true;
}

TimerCallback callback = new TimerCallback(PruneConnectionPoolGroups);
timer = new Timer(callback, null, PruningDueTime, PruningPeriod);
}
finally
{
// Restore the current ExecutionContext
if (restoreFlow)
ExecutionContext.RestoreFlow();
}

return timer;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -666,11 +666,26 @@ internal void Clear()

private Timer CreateCleanupTimer()
{
Timer timer;
// Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever
ExecutionContext.SuppressFlow();
Timer timer = (new Timer(new TimerCallback(this.CleanupCallback), null, _cleanupWait, _cleanupWait));
// Restore the current ExecutionContext
ExecutionContext.RestoreFlow();
bool restoreFlow = false;
try
{
if (!ExecutionContext.IsFlowSuppressed())
{
ExecutionContext.SuppressFlow();
restoreFlow = true;
}

timer = (new Timer(new TimerCallback(this.CleanupCallback), null, _cleanupWait, _cleanupWait));
}
finally
{
// Restore the current ExecutionContext
if (restoreFlow)
ExecutionContext.RestoreFlow();
}

return timer;
}

Expand Down Expand Up @@ -732,7 +747,26 @@ private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectio
// Make sure the timer starts even if ThreadAbort occurs after setting the ErrorEvent.

// timer allocation has to be done out of CER block
Timer t = new Timer(new TimerCallback(this.ErrorCallback), null, Timeout.Infinite, Timeout.Infinite);
Timer timer;
// Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever
bool restoreFlow = false;
try
{
if (!ExecutionContext.IsFlowSuppressed())
{
ExecutionContext.SuppressFlow();
restoreFlow = true;
}

timer = new Timer(new TimerCallback(this.ErrorCallback), null, Timeout.Infinite, Timeout.Infinite);
}
finally
{
// Restore the current ExecutionContext
if (restoreFlow)
ExecutionContext.RestoreFlow();
}

bool timerIsNotDisposed;
try { }
finally
Expand All @@ -743,8 +777,8 @@ private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectio
// Enable the timer.
// Note that the timer is created to allow periodic invocation. If ThreadAbort occurs in the middle of ErrorCallback,
// the timer will restart. Otherwise, the timer callback (ErrorCallback) destroys the timer after resetting the error to avoid second callback.
_errorTimer = t;
timerIsNotDisposed = t.Change(_errorWait, _errorWait);
_errorTimer = timer;
timerIsNotDisposed = timer.Change(_errorWait, _errorWait);
}

Debug.Assert(timerIsNotDisposed, "ErrorCallback timer has been disposed");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,9 @@ private void Restart(object unused)
_timeoutParam.Value = _defaultWaitforTimeout; // If success, reset to default for re-queue.
AsynchronouslyQueryServiceBrokerQueue();
_errorState = false;
Timer retryTimer = _retryTimer;
_retryTimer = null;
retryTimer?.Dispose();
}
}

Expand Down Expand Up @@ -1470,4 +1472,4 @@ internal bool Stop(

return stopped;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,24 @@ private SqlDependencyPerAppDomainDispatcher()
_notificationIdToDependenciesHash = new Dictionary<string, DependencyList>();
_commandHashToNotificationId = new Dictionary<string, string>();

_timeoutTimer = new Timer(new TimerCallback(TimeoutTimerCallback), null, Timeout.Infinite, Timeout.Infinite);
// Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever
bool restoreFlow = false;
try
{
if (!ExecutionContext.IsFlowSuppressed())
{
ExecutionContext.SuppressFlow();
restoreFlow = true;
}

_timeoutTimer = new Timer(new TimerCallback(TimeoutTimerCallback), null, Timeout.Infinite, Timeout.Infinite);
}
finally
{
// Restore the current ExecutionContext
if (restoreFlow)
ExecutionContext.RestoreFlow();
}

SubscribeToAppDomainUnload();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2295,7 +2295,24 @@ internal void ReadSni(TaskCompletionSource<object> completion)

if (_networkPacketTimeout == null)
{
_networkPacketTimeout = new Timer(OnTimeout, null, Timeout.Infinite, Timeout.Infinite);
// Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever
bool restoreFlow = false;
try
{
if (!ExecutionContext.IsFlowSuppressed())
{
ExecutionContext.SuppressFlow();
restoreFlow = true;
}

_networkPacketTimeout = new Timer(OnTimeout, null, Timeout.Infinite, Timeout.Infinite);
}
finally
{
// Restore the current ExecutionContext
if (restoreFlow)
ExecutionContext.RestoreFlow();
}
}

// -1 == Infinite
Expand Down

0 comments on commit afba626

Please sign in to comment.