Skip to content

Commit 69e8353

Browse files
authored
Merge pull request #1131 from ahydrax/timer-queue-deadlock-fix
Fix deadlock when command is being cancelled from two threads.
2 parents 417b221 + 72bb7c0 commit 69e8353

File tree

2 files changed

+14
-6
lines changed

2 files changed

+14
-6
lines changed

src/MySqlConnector/Core/ServerSession.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public bool TryStartCancel(ICancellableCommand command)
9696
{
9797
if (ActiveCommandId != command.CommandId)
9898
return false;
99-
VerifyState(State.Querying, State.CancelingQuery, State.Failed);
99+
VerifyState(State.Querying, State.CancelingQuery, State.ClearingPendingCancellation, State.Closing, State.Closed, State.Failed);
100100
if (m_state != State.Querying)
101101
return false;
102102
if (command.CancelAttemptCount++ >= 10)
@@ -1746,12 +1746,13 @@ private void VerifyState(State state)
17461746
}
17471747
}
17481748

1749-
private void VerifyState(State state1, State state2, State state3)
1749+
private void VerifyState(State state1, State state2, State state3, State state4, State state5, State state6)
17501750
{
1751-
if (m_state != state1 && m_state != state2 && m_state != state3)
1751+
if (m_state != state1 && m_state != state2 && m_state != state3 && m_state != state4 && m_state != state5 && m_state != state6)
17521752
{
1753-
Log.Error("Session{0} should have SessionStateExpected {1} or SessionStateExpected2 {2} or SessionStateExpected3 {3} but was SessionState {4}", m_logArguments[0], state1, state2, state3, m_state);
1754-
throw new InvalidOperationException("Expected state to be ({0}|{1}|{2}) but was {3}.".FormatInvariant(state1, state2, state3, m_state));
1753+
Log.Error("Session{0} should have SessionStateExpected {1} or SessionStateExpected2 {2} or SessionStateExpected3 {3} or SessionStateExpected4 {4} or SessionStateExpected5 {5} or SessionStateExpected6 {6} but was SessionState {7}",
1754+
m_logArguments[0], state1, state2, state3, state4, state5, state6, m_state);
1755+
throw new InvalidOperationException("Expected state to be ({0}|{1}|{2}|{3}|{4}|{5}) but was {6}.".FormatInvariant(state1, state2, state3, state4, state5, state6, m_state));
17551756
}
17561757
}
17571758

src/MySqlConnector/Utilities/TimerQueue.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,14 @@ private TimerQueue()
6767

6868
private void Callback(object? obj)
6969
{
70+
var actionsToBeCalled = new List<Action>();
71+
7072
lock (m_lock)
7173
{
7274
// process all timers that have expired or will expire in the granularity of a clock tick
7375
while (m_timeoutActions.Count > 0 && unchecked(m_timeoutActions[0].Time - Environment.TickCount) < 15)
7476
{
75-
m_timeoutActions[0].Action();
77+
actionsToBeCalled.Add(m_timeoutActions[0].Action);
7678
m_timeoutActions.RemoveAt(0);
7779
}
7880

@@ -86,6 +88,11 @@ private void Callback(object? obj)
8688
UnsafeSetTimer(delay);
8789
}
8890
}
91+
92+
foreach (var action in actionsToBeCalled)
93+
{
94+
action();
95+
}
8996
}
9097

9198
// Should be called while holding m_lock.

0 commit comments

Comments
 (0)