From eab40726be98616b7edac3a600e97b39fc6227cd Mon Sep 17 00:00:00 2001 From: Sona Kurazyan Date: Wed, 10 Nov 2021 09:36:26 +0100 Subject: QFuture: support cancellation of continuation chain through parent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change allows canceling the chain of continuations attached to a future through canceling the future itself at any point of execution of the chain. [ChangeLog][QtCore][Important Behavior Changes] The chain of continuations attached to a future now can be cancelled through cancelling the future itself at any point of the execution of the chain, as it was documented. Previously canceling the future would cancel the chain only if it was done before the chain starts executing, otherwise the cancellation would be ignored. Now the part of the chain that wasn't started at the moment of cancellation will be canceled. Task-number: QTBUG-97582 Change-Id: I4c3b3c68e34d3a044243ac9a7a9ed3c38b7cb02e Reviewed-by: Edward Welbourne Reviewed-by: MÃ¥rten Nordheim --- src/corelib/thread/qfutureinterface.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'src/corelib/thread/qfutureinterface.cpp') diff --git a/src/corelib/thread/qfutureinterface.cpp b/src/corelib/thread/qfutureinterface.cpp index e640114bb0..7512d6174a 100644 --- a/src/corelib/thread/qfutureinterface.cpp +++ b/src/corelib/thread/qfutureinterface.cpp @@ -834,8 +834,18 @@ void QFutureInterfaceBasePrivate::setState(QFutureInterfaceBase::State newState) } void QFutureInterfaceBase::setContinuation(std::function func) +{ + setContinuation(func, nullptr); +} + +void QFutureInterfaceBase::setContinuation(std::function func, + QFutureInterfaceBasePrivate *continuationFutureData) { QMutexLocker lock(&d->continuationMutex); + + if (continuationFutureData) + continuationFutureData->parentData = d; + // If the state is ready, run continuation immediately, // otherwise save it for later. if (isFinished()) { @@ -855,6 +865,24 @@ void QFutureInterfaceBase::runContinuation() const } } +bool QFutureInterfaceBase::isChainCanceled() const +{ + if (isCanceled()) + return true; + + auto parent = d->parentData; + while (parent) { + // If the future is in Canceled state because it had an exception, we want to + // continue checking the chain of parents for cancellation, otherwise if the exception + // is handeled inside the chain, it won't be interrupted even though cancellation has + // been requested. + if ((parent->state.loadRelaxed() & Canceled) && !parent->hasException) + return true; + parent = parent->parentData; + } + return false; +} + void QFutureInterfaceBase::setLaunchAsync(bool value) { d->launchAsync = value; -- cgit v1.2.3