TaskTree: Fix Timeout activation

The activation of one timeout may cancel the other running
timeout. Don't remove all timeouts which are to be activated before
the activation loop. Remove and activate incrementally instead.

Change-Id: I6147fb63b6ef9d6ada034330d98d1c13419012b4
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Jarek Kobus
2023-11-15 23:36:10 +01:00
parent 73bff6d497
commit 9d44d1899d

View File

@@ -2684,29 +2684,6 @@ struct TimerThreadData
// Please note the thread_local keyword below guarantees a separate instance per thread. // Please note the thread_local keyword below guarantees a separate instance per thread.
static thread_local TimerThreadData s_threadTimerData = {}; static thread_local TimerThreadData s_threadTimerData = {};
static QList<TimerData> prepareForActivation(int timerId)
{
const auto it = s_threadTimerData.m_timerIdToTimerData.constFind(timerId);
if (it == s_threadTimerData.m_timerIdToTimerData.cend())
return {}; // the timer was already activated
const system_clock::time_point deadline = it->m_deadline;
QList<TimerData> toActivate;
auto itMap = s_threadTimerData.m_deadlineToTimerId.cbegin();
while (itMap != s_threadTimerData.m_deadlineToTimerId.cend()) {
if (itMap.key() > deadline)
break;
const auto it = s_threadTimerData.m_timerIdToTimerData.constFind(itMap.value());
if (it != s_threadTimerData.m_timerIdToTimerData.cend()) {
toActivate.append(it.value());
s_threadTimerData.m_timerIdToTimerData.erase(it);
}
itMap = s_threadTimerData.m_deadlineToTimerId.erase(itMap);
}
return toActivate;
}
static void removeTimerId(int timerId) static void removeTimerId(int timerId)
{ {
const auto it = s_threadTimerData.m_timerIdToTimerData.constFind(timerId); const auto it = s_threadTimerData.m_timerIdToTimerData.constFind(timerId);
@@ -2722,8 +2699,30 @@ static void removeTimerId(int timerId)
static void handleTimeout(int timerId) static void handleTimeout(int timerId)
{ {
const QList<TimerData> toActivate = prepareForActivation(timerId); const auto itData = s_threadTimerData.m_timerIdToTimerData.constFind(timerId);
for (const TimerData &timerData : toActivate) { if (itData == s_threadTimerData.m_timerIdToTimerData.cend())
return; // The timer was already activated.
const auto deadline = itData->m_deadline;
while (true) {
const auto itMap = s_threadTimerData.m_deadlineToTimerId.cbegin();
if (itMap == s_threadTimerData.m_deadlineToTimerId.cend())
return;
if (itMap.key() > deadline)
return;
const auto it = s_threadTimerData.m_timerIdToTimerData.constFind(itMap.value());
if (it == s_threadTimerData.m_timerIdToTimerData.cend()) {
s_threadTimerData.m_deadlineToTimerId.erase(itMap);
QT_CHECK(false);
return;
}
const TimerData timerData = it.value();
s_threadTimerData.m_timerIdToTimerData.erase(it);
s_threadTimerData.m_deadlineToTimerId.erase(itMap);
if (timerData.m_context) if (timerData.m_context)
timerData.m_callback(); timerData.m_callback();
} }