diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs
index b60027db1f..e3228c3d7d 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs
@@ -55,7 +55,7 @@ public TimeoutState(int value)
private const int AttentionTimeoutSeconds = 5;
- private static readonly ContextCallback s_readAdyncCallbackComplete = ReadAsyncCallbackComplete;
+ private static readonly ContextCallback s_readAsyncCallbackComplete = ReadAsyncCallbackComplete;
// Ticks to consider a connection "good" after a successful I/O (10,000 ticks = 1 ms)
// The resolution of the timer is typically in the range 10 to 16 milliseconds according to msdn.
@@ -2308,9 +2308,9 @@ private void OnTimeoutAsync(object state)
}
}
- private bool OnTimeoutSync()
+ private bool OnTimeoutSync(bool asyncClose = false)
{
- return OnTimeoutCore(TimeoutState.Running, TimeoutState.ExpiredSync);
+ return OnTimeoutCore(TimeoutState.Running, TimeoutState.ExpiredSync, asyncClose);
}
///
@@ -2319,8 +2319,9 @@ private bool OnTimeoutSync()
///
/// the state that is the expected current state, state will change only if this is correct
/// the state that will be changed to if the expected state is correct
+ /// any close action to be taken by an async task to avoid deadlock.
/// boolean value indicating whether the call changed the timeout state
- private bool OnTimeoutCore(int expectedState, int targetState)
+ private bool OnTimeoutCore(int expectedState, int targetState, bool asyncClose = false)
{
Debug.Assert(targetState == TimeoutState.ExpiredAsync || targetState == TimeoutState.ExpiredSync, "OnTimeoutCore must have an expiry state as the targetState");
@@ -2353,7 +2354,7 @@ private bool OnTimeoutCore(int expectedState, int targetState)
{
try
{
- SendAttention(mustTakeWriteLock: true);
+ SendAttention(mustTakeWriteLock: true, asyncClose);
}
catch (Exception e)
{
@@ -2893,7 +2894,7 @@ public void ReadAsyncCallback(IntPtr key, PacketHandle packet, uint error)
// synchrnously and then call OnTimeoutSync to force an atomic change of state.
if (TimeoutHasExpired)
{
- OnTimeoutSync();
+ OnTimeoutSync(true);
}
// try to change to the stopped state but only do so if currently in the running state
@@ -2924,7 +2925,7 @@ public void ReadAsyncCallback(IntPtr key, PacketHandle packet, uint error)
{
if (_executionContext != null)
{
- ExecutionContext.Run(_executionContext, s_readAdyncCallbackComplete, source);
+ ExecutionContext.Run(_executionContext, s_readAsyncCallbackComplete, source);
}
else
{
@@ -3407,7 +3408,7 @@ private void CancelWritePacket()
#pragma warning disable 0420 // a reference to a volatile field will not be treated as volatile
- private Task SNIWritePacket(PacketHandle packet, out uint sniError, bool canAccumulate, bool callerHasConnectionLock)
+ private Task SNIWritePacket(PacketHandle packet, out uint sniError, bool canAccumulate, bool callerHasConnectionLock, bool asyncClose = false)
{
// Check for a stored exception
var delayedException = Interlocked.Exchange(ref _delayedWriteAsyncCallbackException, null);
@@ -3500,7 +3501,7 @@ private Task SNIWritePacket(PacketHandle packet, out uint sniError, bool canAccu
{
SqlClientEventSource.Log.TryTraceEvent(" write async returned error code {0}", (int)error);
AddError(_parser.ProcessSNIError(this));
- ThrowExceptionAndWarning();
+ ThrowExceptionAndWarning(false, asyncClose);
}
AssertValidState();
completion.SetResult(null);
@@ -3535,7 +3536,7 @@ private Task SNIWritePacket(PacketHandle packet, out uint sniError, bool canAccu
{
SqlClientEventSource.Log.TryTraceEvent(" write async returned error code {0}", (int)sniError);
AddError(_parser.ProcessSNIError(this));
- ThrowExceptionAndWarning(callerHasConnectionLock);
+ ThrowExceptionAndWarning(callerHasConnectionLock, asyncClose);
}
AssertValidState();
}
@@ -3547,7 +3548,7 @@ private Task SNIWritePacket(PacketHandle packet, out uint sniError, bool canAccu
internal abstract uint WritePacket(PacketHandle packet, bool sync);
// Sends an attention signal - executing thread will consume attn.
- internal void SendAttention(bool mustTakeWriteLock = false)
+ internal void SendAttention(bool mustTakeWriteLock = false, bool asyncClose = false)
{
if (!_attentionSent)
{
@@ -3589,7 +3590,7 @@ internal void SendAttention(bool mustTakeWriteLock = false)
uint sniError;
_parser._asyncWrite = false; // stop async write
- SNIWritePacket(attnPacket, out sniError, canAccumulate: false, callerHasConnectionLock: false);
+ SNIWritePacket(attnPacket, out sniError, canAccumulate: false, callerHasConnectionLock: false, asyncClose);
SqlClientEventSource.Log.TryTraceEvent(" Send Attention ASync.");
}
finally
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs
index 0b2baeb0be..04086edb47 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs
@@ -2390,9 +2390,9 @@ private void OnTimeoutAsync(object state)
}
}
- private bool OnTimeoutSync()
+ private bool OnTimeoutSync(bool asyncClose = false)
{
- return OnTimeoutCore(TimeoutState.Running, TimeoutState.ExpiredSync);
+ return OnTimeoutCore(TimeoutState.Running, TimeoutState.ExpiredSync, asyncClose);
}
///
@@ -2401,8 +2401,9 @@ private bool OnTimeoutSync()
///
/// the state that is the expected current state, state will change only if this is correct
/// the state that will be changed to if the expected state is correct
+ /// any close action to be taken by an async task to avoid deadlock.
/// boolean value indicating whether the call changed the timeout state
- private bool OnTimeoutCore(int expectedState, int targetState)
+ private bool OnTimeoutCore(int expectedState, int targetState, bool asyncClose = false)
{
Debug.Assert(targetState == TimeoutState.ExpiredAsync || targetState == TimeoutState.ExpiredSync, "OnTimeoutCore must have an expiry state as the targetState");
@@ -2436,7 +2437,7 @@ private bool OnTimeoutCore(int expectedState, int targetState)
{
try
{
- SendAttention(mustTakeWriteLock: true);
+ SendAttention(mustTakeWriteLock: true, asyncClose);
}
catch (Exception e)
{
@@ -2978,7 +2979,7 @@ public void ReadAsyncCallback(IntPtr key, IntPtr packet, UInt32 error)
// synchrnously and then call OnTimeoutSync to force an atomic change of state.
if (TimeoutHasExpired)
{
- OnTimeoutSync();
+ OnTimeoutSync(asyncClose: true);
}
// try to change to the stopped state but only do so if currently in the running state
@@ -3464,7 +3465,7 @@ private void CancelWritePacket()
#pragma warning disable 420 // a reference to a volatile field will not be treated as volatile
- private Task SNIWritePacket(SNIHandle handle, SNIPacket packet, out UInt32 sniError, bool canAccumulate, bool callerHasConnectionLock)
+ private Task SNIWritePacket(SNIHandle handle, SNIPacket packet, out UInt32 sniError, bool canAccumulate, bool callerHasConnectionLock, bool asyncClose = false)
{
// Check for a stored exception
var delayedException = Interlocked.Exchange(ref _delayedWriteAsyncCallbackException, null);
@@ -3555,7 +3556,7 @@ private Task SNIWritePacket(SNIHandle handle, SNIPacket packet, out UInt32 sniEr
SqlClientEventSource.Log.TryTraceEvent(" write async returned error code {0}", (int)error);
AddError(_parser.ProcessSNIError(this));
- ThrowExceptionAndWarning();
+ ThrowExceptionAndWarning(false, asyncClose);
}
AssertValidState();
completion.SetResult(null);
@@ -3592,7 +3593,7 @@ private Task SNIWritePacket(SNIHandle handle, SNIPacket packet, out UInt32 sniEr
{
SqlClientEventSource.Log.TryTraceEvent(" write async returned error code {0}", (int)sniError);
AddError(_parser.ProcessSNIError(this));
- ThrowExceptionAndWarning(callerHasConnectionLock);
+ ThrowExceptionAndWarning(callerHasConnectionLock, false);
}
AssertValidState();
}
@@ -3602,7 +3603,7 @@ private Task SNIWritePacket(SNIHandle handle, SNIPacket packet, out UInt32 sniEr
#pragma warning restore 420
// Sends an attention signal - executing thread will consume attn.
- internal void SendAttention(bool mustTakeWriteLock = false)
+ internal void SendAttention(bool mustTakeWriteLock = false, bool asyncClose = false)
{
if (!_attentionSent)
{
@@ -3649,7 +3650,7 @@ internal void SendAttention(bool mustTakeWriteLock = false)
UInt32 sniError;
_parser._asyncWrite = false; // stop async write
- SNIWritePacket(Handle, attnPacket, out sniError, canAccumulate: false, callerHasConnectionLock: false);
+ SNIWritePacket(Handle, attnPacket, out sniError, canAccumulate: false, callerHasConnectionLock: false, asyncClose);
SqlClientEventSource.Log.TryTraceEvent(" Send Attention ASync.", "Info");
}
finally