82 Commits

Author SHA1 Message Date
Ivan Solovev
b0e82f5981 QFutureInterfaceBase: rework setContinuation() overload set
Add new overloads to make sure that we can pass continuation data
even for the continuations with context. The new overloads
intentionally do not expose QFutureInterfaceBasePrivate pointer,
because they would be used in the inline code (see QTBUG-117514).
The overload with a context provides a continuation future as a
QVariant, because that is the easiest way to keep the
QFutureInterface<T> object alive without exposing the template
type T to a non-templated exported base class. We cannot pass the
QFutureInterfaceBase because of the reference count logic, which
contains two different counters: for base class (void case), and
for the interface that holds an actual type T.

This patch is a pre-requisite for a follow-up patch that would
introduce the ability to cancel the entire continuation
chain from the first QFuture object of the chain, even if
that QFuture is already finished.

Note that the pre-existing QFutureInterface::cancel() code
relies on the fact that only then-continuations provide
continuation data. The onFailed() and onCanceled() handlers
never provide it, even when they were supposed to be executed
in the same thread.
To keep the old behavior on the cancel() method, introduce
a new ContinuationType enum and make sure that the type is
properly set when providing a continuation data.

The new overloads also allow to get rid of the template
QtPrivate::watchContinuation() helper method. The exported
Impl should stay for BC reasons. This patch implements it
in terms of the new setContinuation() overload.

During the development of this patch it was important to
verify that the behavior of all public and/or exported
methods stays unchanged. It was done by running the tst_qfuture
binary that was originally compiled with the old QtCore version
against the updated QtCore library.

Task-number: QTBUG-130662
Change-Id: I2bd5821846561d18c198205f3c57d3f0dacbb94b
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2025-02-11 12:19:45 +01:00
Ivan Solovev
04b5d2b94f QFuture: prevent the continuations from being executed twice
On some very rare cases the continuation could be executed twice in a
multithreaded scenario. Consider the following example:

  auto f = QtConcurrent::run(someFunction);
  f.then(someOtherFunction);

Assuming that QtConcurrent::run() is executed on Thread B, and the
continuation is attached in Thread A, the following call stack is
possible:
1. Thread B: someFunction() is finished
2. Thread B: QFutureInterface::reportFinished() is called
3. Thread B: QFutureInterfaceBase::reportFinished() is called and
             finished.
4. Thread A: then() is called. It checks that the future is already
             finished, so the attached continuation is executed
             immediately.
5. Thread B: QFutureInterfaceBase::runContinuation() is executed.
             At this point it sees that a continuation exists, and
             executes it again.

Step 5 will lead to a crash, because we'll try to access a moved-from
QPromise.

To fix the issue, introduce a flag that is explicitly used to test if
the continuation was already executed or not.

The pre-existing code already uses a concept of a continuation state,
but it cannot be easily extended without convering it from an enum
to flags, because the canceled continuation should still be called
in order to actually execute the onCanceled() handler.

Wrapping QFIBP::ContinuationState into QFlags would increase its size
from 1 to 4 bytes, and manually treating the enum as flags will result
in a more complicated code. So, I simply picked the approach of adding
an explicit flag for this case.

Writing a unit-test is not really possible, but I verified that the
reproducer from the linked Jira ticket does not crash anymore.

Amends dfaca09e85a49d2983bb89893bfbe1ba4c19eab4 that introduced the
continuations, so picking to all active Qt 6 branches.

Fixes: QTBUG-118032
Pick-to: 6.9 6.8 6.5
Change-Id: I3e07722495e38367e8e4be2eded34140e22b0053
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2025-02-11 12:19:40 +01:00
Ahmad Samir
185cba6e95 Replace qdebug.h includes in public headers with forward-declarations
qdebug.h includes many Qt and STL headers, so if you include a Qt header
you get all those transitive includes, which may affect build time.

- Where appropriate use the printf-like syntax of qDebug() and co.,
  these don't need the QDebug streaming operators
- qfloat16 is used in an inline member function, so include it
  explicitly

[ChangeLog][Potentially Source Incompatible Changes] Various Qt public
headers don't include QDebug any more; if you need QDebug's streaming
you'll have to include it in your code.

Task-number: QTBUG-132439
Pick-to: 6.9
Change-Id: I750587e17a3b38fa226cd3af8eaccc8da580f436
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2025-01-15 13:28:16 +02:00
Ahmad Samir
158f2c95c8 Include climits explicitly instead of relying on transitive includes
Pick-to: 6.9 6.8 6.5
Change-Id: Ib55b337aa6e0a93c7ac7ee9bf492784cc81808d7
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
2025-01-13 20:22:11 +00:00
Philip Schuchardt
2bc82f6a11 QFuture: Fix for heap-use-after-free on qfutureinterface watch
Replace deleteLater with destroyWatcher.

If the continuation is called from a separate thread,
emit watcher->run() can't detect thatthe watcher has
been deleted in the separate thread, causing a race
condition and potential heap-use-after-free issue inside
QObject::doActivate. destroyWatcher forces the deletion
of the watcher to occur after emit watcher->run()
completes and prevents the race condition.

Fixes: QTBUG-126013
Fixes: QTBUG-127880
Pick-to: 6.8 6.7
Change-Id: Id5f80ad0ec3fbd2d9c1e0d134aecd6b08ba2c79c
Reviewed-by: Arno Rehn <a.rehn@menlosystems.com>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2024-08-19 20:20:56 +00:00
Mårten Nordheim
c88a1b3f37 QFutureInterface: remove comment that was never true
Even in the original patch where the comment was added the
callouts were made with the lock held.

Change-Id: Id8d122010d2195d83ddd4fdaf638f7fc4ac8163d
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
2024-03-15 23:16:50 +01:00
Jarek Kobus
63b2cf8a45 QFutureWatcher: Fix race for initial emission of resultReadyAt()
When connecting a QFutureWatcher to the QFuture it will connect to the
output interface, which will queue up events to notify about the current
state. This happens in the thread of the QFutureWatcher.

Since 07d6d31a4c0c17d8c897d783a9b0841df6834b02 unfortunately the sending
of those events was done outside the lock, meaning the worker-thread
could _also_ send events at the same time, leading to a race on which
events would be sent first.

To fix this we move the emission of the events back into the lock
and because it is now inside the lock again anyway, we will revert
back to posting the callout events immediately, so this patch also
partially reverts 07d6d31a4c0c17d8c897d783a9b0841df6834b02

Fixes: QTBUG-119169
Pick-to: 6.7 6.6
Change-Id: If29ab6712a82e7948c0ea4866340b6fac5aba5ef
Reviewed-by: Arno Rehn <a.rehn@menlosystems.com>
Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
2024-03-15 11:42:36 +00:00
Nodir Temirkhodjaev
1e836fff18 QFutureInterface: Rename "interface" variables to "iface"
On Windows the "interface" is defined as "struct".
Do not #undef it to fix a unity build.

Task-number:  QTBUG-122980
Pick-to: 6.7
Change-Id: I9379c996d8b67b16a8b825af0ff3469111533291
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2024-03-05 19:58:15 +03:00
Ivan Solovev
11333a0972 QFuture: immediately delete watcher after the context is destroyed
We used deleteLater(), which was triggering ASAN use-after-free error.
Apparently, what could happen is that after the context was destroyed,
we called deleteLater(), but if at this point the previous future got
finished, we still tried to emit watcher->run() to execute the
continuation. And then the watcher got deleted.

This patch replaces deleteLater() with a plain delete call. This looks
safe, because the watcher is only accessed while holding the lock.

Amends 59e21a536f7f81625216dc7a621e7be59919da33.

Fixes: QTBUG-120302
Pick-to: 6.7 6.6
Change-Id: Ia32f20bfe8daea2e2346f3d446c978ae305d2f68
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2024-01-09 00:55:41 +00:00
Arno Rehn
59e21a536f QFuture: Don't use QFutureCallOutInterface for continuations
This patch replaces the QBasicFutureWatcher that was used for
continuations with context objects with a smaller QObject-based wrapper
that works directly from the actual continuation.
The idea stays the same: In order to run continuations in the thread of
a context object, we offload the continuation invocation to the
signal-slot mechanism.
Previously, we've hooked into QFuture with QFutureCallOutInterface to
emit a signal and trigger continuation invocation. However, it is much
easier and robust to emit that signal from the continuation itself.

This sidesteps the locking issues that QFutureCallOutInterface handling
presents. QFutureCallOutInterface basically requires any consumer to
only access the QFuture after all events have been posted and the
internal mutex unlocked, i.e. on the next cycle of the event loop.

Continuations do not impose this restriction; runContinuation()
explicitly unlocks the internal mutex before calling the continuation.

This fixes a deadlock when using QFuture::then(context, ...) where
the paren future is resolved from the same thread that the context
object lives in.

Fixes: QTBUG-119406
Fixes: QTBUG-119103
Fixes: QTBUG-117918
Fixes: QTBUG-119579
Fixes: QTBUG-119810
Pick-to: 6.7 6.6
Change-Id: I112b16024cde6b6ee0e4d8127392864b813df5bc
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
2023-12-13 21:54:00 +01:00
Thiago Macieira
a7f227f56c Make qYieldCpu() public API
Rewritten to be a bit simpler, added a few more yield/YieldProcessor
alternatives, added RISC-V support.

[ChangeLog][QtCore] Added qYieldCpu() function.

Fixes: QTBUG-103014
Change-Id: I53335f845a1345299031fffd176f59032e7400f5
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
2023-07-25 07:21:56 -07:00
Marc Mutz
56651915e8 QFutureInterface: port to new SlotObjUniquePtr
... removing a ### comments to that effect.

Pick-to: 6.6
Change-Id: I635ca9593ec72a66d328ff6de61cd311c1b4e89f
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
2023-07-19 13:38:02 +02:00
Marc Mutz
3fb0208d4b QBasicFutureWatcher: get rid of the Private
It's not needed anymore, because the class is no longer part of the ABI.

Pick-to: 6.6
Change-Id: Idfacc6023288ce603b30ab5aa904106e8c850444
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
2023-07-13 17:46:05 +02:00
Marc Mutz
d41db62154 Move QBasicFutureWatcher behind the ABI boundary
... and out of QtPrivate.

No inline API requires it anymore, so move it into the only TU using
it. Can't move it into the unnamed namespace because of the friend
declaration in QFutureInterfaceBase.

Pick-to: 6.6
Change-Id: I27452960492bc1193a4d0eaeb2acd913d4dd02a5
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
2023-07-13 08:24:02 +00:00
Marc Mutz
dfd07205e5 QFuture: Extract Method watchContinuation() (DRY && SCARY)
The old code violated the following principles:

- DRY: the same code occurred 3× in the code-base

- SCARY: the vast majority doesn't actually depend on template
  arguments, causing template bloat

Solve both with a tiered Extract Method.

We cannot change the order of the operations performed on
QBasicFutureWatcher, in particular not the connect() to the
contination w.r.t. setFuture(), so we cannot leave the connect to the
continuation lambda outside the function, as it would mean to also
leave the setFuture() call outside.

Thanks to Volker's makeCallableObject(), we can, however, type-erase
the lambda using QSlotObjectBase, which is what connect() internally
creates, anyway, therefore bringing the whole function behind the ABI
boundary.

As a non-QObject, non-QMetaObject friend, we're lacking support for
actually doing something useful with a QSlotObjectBase, but that can
be fixed in the implementation now. The interface is stable, which is
what matters for 6.6 now.

This will allow a subsequent commit to drag QBasicFutureWatcher behind
the ABI boundary, unexporting it.

Saves a whopping 8KiB in tst_qfuture text size on optimized C++20
Linux AMD64 GCC9 builds.

Pick-to: 6.6
Done-with: Fabian Kosmale <fabian.kosmale@qt.io>
Change-Id: I0e5c2564907d92f6938689ab249be11fc0332ba5
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Arno Rehn <a.rehn@menlosystems.com>
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2023-07-13 09:50:42 +02:00
Marc Mutz
df96d39c04 ThreadPoolThreadReleaser: add Q_NODISCARD_CTOR
QUIP: 19
Pick-to: 6.6
Change-Id: I465a2ef8edc103f0655a7732f3aaaf18748854c4
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2023-07-13 00:15:33 +02:00
Ahmed Essam
1f22fc995a Fix segfault when using qfuture continuations with move only types
When using move-only types, continuations args are set using takeResult
function, which has the side effect of invalidating the QFutureInterface
associated with the promise/futures by:

1. setting isValid to false
2. setting the state to NoState

And when the promise is destroyed, it tries to run the continuations if
`finished()` is not called, which is done by checking the Finished bit
in the state. But since the continuation has been run before, and the
state has been set to NoState it tries to run the continuation again
causing a segfault. Multiple solutions come in mind:

1. don't run the continuation if the state is NoState, but this would
   break the case when an empty promise is destroyed
2. check inside the continuation if it has been run before, and if so
   don't run it again, but this seems hacky since we don't want the
   continuation to be run twice, and it should break if it did.
3. when invalidating the promise leave the state as is, and change
   isValid only to false, which changes the current behavior, but is
   still compatible with the documentation which states only that
   isValid will return false if takeResult is called

I chose option 3

I also extended some tests to test for move only types, and added a test
that continuations run when a promise is finished. This simple case
would segfault before with move only types.

Fixes: QTBUG-112513
Pick-to: 6.5 6.6
Change-Id: Ie225ac4fdf618e4edfb0efd663d6c7fd6b916dbd
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
2023-06-10 14:28:13 +00:00
Arno Rehn
07d6d31a4c QFuture: Gracefully handle a destroyed context in continuations
This patch relaxes the requirements on the context object of
continuations. Instead of having to stay alive during execution of the
whole chain, it now only has to stay alive during setup of the chain.
If the context object is destroyed before the chain finishes, the
respective future is canceled.

This patch works by using QFutureCallOutInterface and signals instead
of direct invocation of the continuation by the parent future, similar
to how QFutureWatcher is implemented.
If a continuation is used with a context object, a QBasicFutureWatcher
is connected to the QFuture via a QFutureCallOutInterface. When the
future finishes, QBasicFutureWatcher::finished() triggers the
continuation with a signal/slot connection.
This way, we require the context object to stay alive only during setup;
the required synchronization is guaranteed by the existing event and
signal-slot mechanisms. The continuation itself does not need to know
about the context object anymore.

[ChangeLog][QtCore][QFuture] Added support for context objects of
continuations being destroyed before the continuation finishes. In
these cases the future is cancelled immediately.

Fixes: QTBUG-112958
Change-Id: Ie0ef3470b2a0ccfa789d2ae7604b92e509c14591
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
2023-05-30 21:42:46 +02:00
Ahmad Samir
4538bbf4a6 Misc.: Fix some narrowing integral conversion warnings
Drive-by change: use QByteArrayView instead of allocating a QByteArray.

Change-Id: Iaf7acbbdb4efbb101b73b30061ce38dd1fa99ca3
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2023-04-25 06:15:36 +02:00
Ivan Solovev
9b4b32ec98 Long live QtFuture::makeReadyVoidFuture() and QtFuture::makeReadyValueFuture()
[ChangeLog][QtCore][QFuture] Added QtFuture::makeReadyVoidFuture()
and QtFuture::makeReadyValueFuture().

Basically, these methods behave like QtFuture::makeReadyFuture(), but
QtFuture::makeReadyValueFuture() does not have a "const QList<T> &"
specialization returning QFuture<T> instead of QFuture<QList<T>>,
which allows it to always behave consistently.

This patch also introduces usage of the new methods around qtbase.

Task-number: QTBUG-109677
Change-Id: I89df8b26d82c192baad69efb5df517a8b182995f
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
2023-04-05 13:38:15 +02:00
Ivan Solovev
502a7706b9 QFutureInterface: add a warning when an existing continuation is overwritten
... and also extend the documentation to explain this case explicitly.

Fixes: QTBUG-107545
Pick-to: 6.5 6.2
Change-Id: I9414cc677b037989de60e97871485018e5c8a569
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2023-03-28 09:45:55 +01:00
Ivan Solovev
b34bea5e96 QFuture: fix continuation cleanup
Not clearing the continuationData could lead to use-after-free when
there is an attempt to cancel an already finished future, which belongs
to an already-destroyed promise.

This patch fixes it be explicitly resetting continuationData to nullptr
in the clearContinuation() method, which is called from the QPromise
destructor.

Task-number: QTBUG-103514
Pick-to: 6.5 6.4 6.2
Change-Id: I6418b3f5ad04f2fdc13a196ae208009eaa5de367
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2023-02-15 15:12:12 +01:00
Marc Mutz
df9d882d41 Port from container.count()/length() to size()
This is semantic patch using ClangTidyTransformator:

  auto QtContainerClass = expr(hasType(namedDecl(hasAnyName(<classes>)))).bind(o)
  makeRule(cxxMemberCallExpr(on(QtContainerClass),
                             callee(cxxMethodDecl(hasAnyName({"count", "length"),
                                                  parameterCountIs(0))))),
           changeTo(cat(access(o, cat("size"), "()"))),
           cat("use 'size()' instead of 'count()/length()'"))

a.k.a qt-port-to-std-compatible-api with config Scope: 'Container'.

<classes> are:

    // sequential:
    "QByteArray",
    "QList",
    "QQueue",
    "QStack",
    "QString",
    "QVarLengthArray",
    "QVector",
    // associative:
    "QHash",
    "QMultiHash",
    "QMap",
    "QMultiMap",
    "QSet",
    // Qt has no QMultiSet

Change-Id: Ibe8837be96e8d30d1846881ecd65180c1bc459af
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
2022-10-04 07:40:08 +02:00
Sona Kurazyan
24dedaeaa1 QFuture: fix handling of cancelled continuation chain
To support cancellation of continuations attached via the parent future,
for each future returned by a continuation we store a pointer to its
parent (i.e. future the continuation is attached to). Later, before
executing a continuation, we go through chain of parents and check if
any of them is cancelled. However, if one of the parents is destroyed
while the chain is executing, the next continuations' parent pointers
will become invalid. So storing the parent pointers isn't safe.

This commit changes the logic of handling the cancelled continuation
chain in the following way:

- Instead of storing a parent pointer in the continuation future's data,
  we do the opposite: we store a pointer to continuation's future in the
  parent.
- When a future is cancelled, we mark all continuation futures in the
  chain with a flag indicating that the chain is cancelled.
- To guarantee that the pointers to continuation future's data don't
  become invalid, we clean the continuation (that stores a copy of its
  future's data and keeps it alive) only when the associated promise
  is destructed, instead of cleaning it after the continuation is run.

Fixes: QTBUG-105182
Fixes: QTBUG-106083
Pick-to: 6.2 6.3 6.4
Change-Id: I48afa98152672c0fc737112be4ca3b1b42f6ed30
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2022-09-21 01:18:31 +02:00
Sona Kurazyan
73e1bc09e6 Move QFutureInterfaceBase::cleanContinuation() to removed_api
This method isn't used anymore, but we can't remove it entirely for BC
reasons, because it was called from inline code.

Pick-to: 6.4
Change-Id: I9183c666c466030787ac7c2386706b50abf23eaa
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
2022-06-22 14:32:01 +02:00
Kai Köhne
9d2cc4dd76 Fix typos in docs and comments
Found by codespell

Pick-to: 6.4
Change-Id: Ie3e301a23830c773a2e9aff487c702a223d246eb
Reviewed-by: Nicholas Bennett <nicholas.bennett@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
2022-06-15 21:31:02 +02:00
Lucie Gérard
05fc3aef53 Use SPDX license identifiers
Replace the current license disclaimer in files by
a SPDX-License-Identifier.
Files that have to be modified by hand are modified.
License files are organized under LICENSES directory.

Task-number: QTBUG-67283
Change-Id: Id880c92784c40f3bbde861c0d93f58151c18b9f1
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Reviewed-by: Jörg Bornemann <joerg.bornemann@qt.io>
2022-05-16 16:37:38 +02:00
Thiago Macieira
5302857f5a Atomics: workaround GCC 12 warning about overflowing d->state
I don't see a way this can be anything but a bogus warning.

In member function ‘std::__atomic_base<_IntTp>::__int_type std::__atomic_base<_IntTp>::fetch_or(__int_type, std::memory_order) [with _ITp = int]’,
    inlined from ‘static T QAtomicOps<X>::fetchAndOrRelaxed(std::atomic<T>&, typename QAtomicAdditiveType<T>::AdditiveT) [with T = int; X = int]’ at qatomic_cxx11.h:449:33,
    inlined from ‘T QBasicAtomicInteger<T>::fetchAndOrRelaxed(T) [with T = int]’ at qbasicatomic.h:168:36,
    inlined from ‘int switch_on(QAtomicInt&, int)’ at qfutureinterface.cpp:97:31,
    inlined from ‘void QFutureInterfaceBase::setThrottled(bool)’ at qfutureinterface.cpp:194:18:
atomic_base.h:648:33: warning: ‘unsigned int __atomic_or_fetch_4(volatile void*, unsigned int, int)’ writing 4 bytes into a region of size 0 overflows the destination [-Wstringop-overflow=]

A few more of those appear in other modules. I'm not fixing them all,
assuming GCC will soon fix the warning.

Pick-to: 6.2 6.3
Change-Id: I7fb65b80b7844c8d8f26fffd16e93f68e278d048
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
2022-05-11 12:50:08 -07:00
Marc Mutz
c847f0091d QFutureInterface: use (new) qYieldCpu() instead of _mm_pause()
This loop here was a lonesome instance of a CAS loop in which adding
_mm_pause() was simple, because the code didn't use the usual pattern

  do {
     construct new value
  } while (!testAndSet)

we use everywhere else in Qt.

In search of an elegant pattern that would allow to apply
qYieldCpu()/_mm_pause() to those idiomatic CAS loops, too, I've
reached for a lambda to construct the new value. This should apply to
all (tight) CAS loops, and may form the basis of an API extension
whereby we take that lambda as a function argument to encapsulate the
CAS loop in an algorithm (a function).

Pick-to: 6.3
Change-Id: Id4a8f174dd812aa26f0b163e943bd4558e5e6a7b
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
2022-04-30 23:54:38 +02:00
Thiago Macieira
f02879a97a QFutureInterface: insert x86 PAUSE in tight CMPXCHG loop
From the Intel Software Optimization Manual[1], Chapter 11 ("Multi-core
and Hyper-Threading Technology"), offers:

User/Source Coding Rule 14. (M impact, H generality) Insert the PAUSE
instruction in fast spin loops and keep the number of loop repetitions
to a minimum to improve overall system performance.

See section 11.4.2 for an explanation of why this is a good idea.

[1] https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html#inpage-nav-5

Pick-to: 6.3
Change-Id: I7fb65b80b7844c8d8f26fffd16e94088dad1ceee
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
2022-04-26 19:38:12 -07:00
Marc Mutz
da0f72ebb8 QEvent: start to de-inline copy ctor and clone() of all subclasses
There's no advantage to them being inline: Absent de-virtualisation,
clone() is only supposed to be called through the vtable, and the copy
ctor is only supposed to be used in the implementation of clone().

And when the compiler de-virtualises, we don't want the code
duplication associated with inlining.

Enforce this by introducing new macros to hide the boilerplate.

This fixes missing out-of-line dtors in:
- QSinglePointEvent
- QApplicationStateChangeEvent
- QFutureCallOutEvent

Wrong covariant return in:
- QFutureCallOutEvent

And missing clone() reimplementations in:
- QCloseEvent
- QIconDragEvent
- QShowEvent
- QHideEvent
- QDragEnterEvent
- QDragLeaveEvent

While these don't carry extra data or members, a dynamic_cast of the
result of clone() as well as using the expected covariant return value
would fail:

   QShowEvent *e = ~~~;
   QShowEvent *e2 = e->clone(); // ERROR: converting QEvent* to QShowEvent*

Check that reimplementing clone() is binary compatible (covariant
returns may change the numerical pointer value returned, cf.
https://community.kde.org/Policies/Binary_Compatibility_Issues_With_C%2B%2B).

The copy-assignment operator stays inline for the time being, as the
goal is to = delete it in the future.

This patch covers, roughly, QtCore and QtGui.

[ChangeLog][QtGui][QEvent subclasses] Fixed missing clone()
reimplementations on QCloseEvent, QIconDragEvent, QShowEvent,
QHideEvent, QDragEnterEvent, and QDragLeaveEvent.

Task-number: QTBUG-45582
Task-number: QTBUG-97601
Change-Id: Ib8a0519dbe85a7a8da61050d48be338004dfa69a
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2022-04-14 19:07:16 +02:00
Marc Mutz
5d6d127271 QFutureInterface: optimize atomic load
As all other 20+ users of the state variable, use a relaxed atomic
load under the protection of the mutex. There's no need for the
loadAcquire() that the implicit conversion operator uses under the
hood, because a) we're under mutex protection and b) the state doesn't
guard any other data but itself.

Found by disabling said implicit conversion operators.

Change-Id: I2a76242271cec96175cde503ca883805db6b9212
Reviewed-by: David Faure <david.faure@kdab.com>
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
2022-04-05 13:47:15 +02:00
Sona Kurazyan
b292928e35 Optimize ContinuationWrapper used for support of move-only continuations
After QFuture continuations became non-copyable (see earlier commits),
we have to always use ContinuationWrapper to save the continuations
inside std::function, since it requires the callable to be copyable.
Optimize the wrapper, by storing the callable directly (instead of using
a ref-counted QSharedPointer) and introducing a fake copy-constructor
that makes sure that it's never called.

Pick-to: 6.3 6.2
Change-Id: I0ed5f90ad62ede3b5c6d6e56ef58eb6377122920
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2022-01-21 01:51:20 +01:00
Sona Kurazyan
a8794503eb Fix memory leaks when capturing a QFuture in its continuation
Capturing a QFuture in the continuations attached to it results in
memory leaks. QFuture's ref-counted data can only be deleted when the
last copy referencing the data gets deleted. The saved continuation
that keeps a copy of the future (as in case of the lambda capture) will
prevent the data from being deleted. So we need to manually clean the
continuation after it is run. But this doesn't solve the problem if the
continuation isn't run. In that case, clean the continuation in the
destructor of the associated QPromise.

To avoid similar leaks, internally we should always create futures via
QPromise, instead of the ref-counted QFutureInterface, so that the
continuation is always cleaned in the destructor. Currently QFuture
continuations and QtFuture::when* methods use QFutureInterface directly,
which will be fixed by the follow-up commits.

Fixes: QTBUG-99534
Pick-to: 6.3 6.2
Change-Id: Ic13e7dffd8cb25bd6b87e5416fe4d1a97af74c9b
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2022-01-21 01:51:20 +01:00
Marc Mutz
2dea20e4b0 QFutureCallOutInterface: de-inline dtor
Pick-to: 6.3
Task-number: QTBUG-45582
Change-Id: I5f3411e1dcea4b76fb0e729f612516db3163c93a
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2022-01-05 21:29:31 +01:00
Sona Kurazyan
eab40726be QFuture: support cancellation of continuation chain through parent
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 <edward.welbourne@qt.io>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2021-11-13 18:13:08 +01:00
Sona Kurazyan
ce59ccb334 Optimize QPromise destructor
Unify cancel and finish in QPromise destructor in a single call. This
saves us one extra mutex lock and atomic state change.

Task-number: QTBUG-84977
Change-Id: Iac06302c39a2863008b27325fcf6792d4f58c8ae
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2021-10-08 17:17:20 +02:00
Sona Kurazyan
02f521a59c Allocate progress related data on demand
Some of the data members related to progress reporting (min, max and
text) aren't used when user doesn't want manual progress reporting, so
the data for them can be allocated on demand, when the user explicitly
sets them. Note, that we still need to always create other related data
(current value and progress timer), since in the non-manual mode
progress is still reported by incrementing the current value each time
a new result is reported.

Task-number: QTBUG-92045
Change-Id: I1e5bd17de2613a6ea72ccff0029812f67686708b
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
2021-06-12 03:08:59 +02:00
Sona Kurazyan
6460c3c33d QFuture: put the result store and the exception store in a union
QFuture doesn't need both at the same time, calling QFuture::result(s)
either returns a result or throws an exception. Store result and
exception stores in a union, to reduce the memory.

Also added a note for making the ResultStoreBase destructor non-virtual
in Qt 7.

Task-number: QTBUG-92045
Change-Id: I7f0ac03804d19cc67c1a1466c7a1365219768a14
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2021-06-12 03:08:59 +02:00
Giuseppe D'Angelo
d598066dcf QFutureInterface(Base): code tidies
refT()/derefT() can be marked noexcept; we don't care about not
overflowing the refcounter as a precondition. (This is BC, as no
compiler mangles noexcept.) This in turn allows to mark a constructor
calling refT() as noexcept.

Driveby: mark also the same functions to not be `const` in Qt 7.
They clearly are meant to modify *this, and constness only works
because of the unmanaged (raw) d-pointer.

Change-Id: I8d7d365640ff2e1cedc0a234c9abccdfc95ba6e3
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
2021-06-08 22:41:58 +02:00
Giuseppe D'Angelo
49c5724cb8 QPromise/QFutureInterface: in Qt 7 take std::exception_ptr by const-ref
std::exception_ptr is a reference-counted "smart pointer", so we
shouldn't copy it around freely. Unfortunately QFutureInterface
has exported functions taking it by value, so we can't just change
the signatures and keep BC. Simply prepare the code for Qt 7.

Change-Id: Ic5aae6a095c8c842872a40db440c99d2dfe371f1
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
2021-06-08 22:41:58 +02:00
Giuseppe D'Angelo
41774f7597 QPromise/QFuture: fix value semantics
In random order:

* QFutureInterfaceBase has a d-pointer, and copy semantics. So,
"naturally" extend it to support move semantics as well. (These get
used by QPromise/QFuture, as they both hold a QFutureInterface*
as a data member). The only addition needed is a check for a null
d-pointer in the destructor.

Drive by, reorganize the code for the copies, and use copy-and-swap
instead of the hand-rolled solution. Also, add a free swap()
overload, and mark the existing one as candidate for inlining
in Qt 7 (doesn't need to be an exported function).

* QFutureInterface inherits QFutureInterfaceBase, again with value
semantics. To be honest, I'm not sure why QFutureInterfaceBase is
polymorphic -- could be a design mistake, as polymorphic classes
don't mix with value semantics. Anyways, reorganize the code for
copies, apply copy-and-swap, and add move semantics. This requires
adding a check into derefT().

* Finally, QPromise was already move-only, but had broken move
semantics: the move constructor was not noexcept (!) and it actually
allocated memory (!!!). Fix that one (can be defaulted now), and
streamline the move assignment via the proper macro.

Drive by, fix the signature of the constructor from QFutureInterface
(take const-ref, not plain ref -- it's eventually copied, so it
can keep the const), and add another internal constructor from
rvalue QFutureInterface that moves from it.

Change-Id: I9d61a9dd4d45f34942d8f34416baa118c0307390
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
2021-05-22 03:20:32 +02:00
Qt CI Bot
f5e300bf6a Merge integration refs/builds/qtci/dev/1616415197 2021-03-22 16:45:12 +00:00
Fabian Kosmale
abd7496fba QFutureInterfaceBasePrivate: reorder members to save 8 bytes
And use in-class member initialization where applicable.

Task-number: QTBUG-92045
Change-Id: I54715709f2d8e54017311f45016c16d86ed3078b
Reviewed-by: Karsten Heimrich <karsten.heimrich@qt.io>
2021-03-22 13:12:15 +01:00
Fabian Kosmale
e07aec7eaa QFuture: cleanup headers
Do not include vector; we currently do not use std::vector, and the plan
is to use QList when that one supports move-only types.
Use QMutexLocker instead of std::mutex_locker, considering that the
former is already included with <QMutex>.
Use forward declarations where applicable.
Add header which were currently only indirectly included (to make
QtCreator's code model happy).

Change-Id: I37d5cd3982047a6d8a3132fd66571878298039b3
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
Reviewed-by: Karsten Heimrich <karsten.heimrich@qt.io>
2021-03-22 10:47:13 +01:00
Sona Kurazyan
95cea24fa2 Fix memory leaks in QFuture's continuations
There were two issues:

- Some of the continuations were allocating memory for the
continuation's context dynamically, but deleting the allocated memory
only if they were actually invoked. Since the continuations may not be
invoked at all, this could cause memory leaks. Fixed by postponing the
allocations to the point when the continuations need to be invoked.

- In other cases the parent future is captured by copy in the
continuation's lambda, which is then saved in the parent. This causes
the following problem: the data of the ref-counted parent will be
deleted as soon as its last copy gets deleted. But the saved
continuation will prevent it from being deleted, since it holds a copy
of parent. To break the circular dependency, instead of capturing the
parent inside the lambda, we can pass the parent's data directly to
continuation when calling it.

Fixes: QTBUG-87289
Change-Id: If340520b68f6e960bc80953ca18b796173d34f7b
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
Reviewed-by: Karsten Heimrich <karsten.heimrich@qt.io>
(cherry picked from commit 5d26d40a5596be048be87f309df9264bac741be9)
Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
2020-12-01 15:59:12 +01:00
Ivan Solovev
1d8dd9a02c Track progress range in QFutureInterface::setProgressValue
Previously QFutureInterface::setProgressValue was silently ignoring
the progress range and allowed to set any progress value.
Also no checks were performed in QFutureInterface::setProgressRange,
which allowed the user to set minimum > maximum.

Add checking of the current progress range, when settings the
progress value.
Add checks for minimum and maximum values while setting the progress
range.
The implementation of the checks is mostly based on the logic
that is used in QProgressBar.
- If maximum is smaller than minimum, minimum becomes the only legal
value.
- If the current progress value falls outside the new range, the
progress value is set to be minimum.
- If both progressMinimum() and progressMaximum() return 0, the
current progress range is considered to be unused, and any progress
value can be set.
- When setting the value using setProgressValue(), if the value falls
out of the progress range, the method has no effect.

Task-number: QTBUG-84729
Change-Id: I29cf4f94b8e98e1af30dd46fbdba39c421cf66bf
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
2020-11-17 16:16:31 +01:00
Sona Kurazyan
9efe2a8603 Fix QFuture::waitForFinished to wait until QFuture is started
Currently QFuture::waitForFinished() exits as soon as the future is not
in the running state. If the user calls it before
QPromise::reportStarted() is called, it will exit immediately, because
nothing is running yet. Fix the behavior to wait for the finished state.

[ChangeLog][Important Behavior Changes][QtCore] Fixed the behavior of
QFuture::waitForFinished() to wait until the future is actually in the
finished state, instead of exiting as soon as it is not in the running
state. This prevents waitForFinished() from exiting immediately, if at
the moment of calling it the future is not started yet.

Task-number: QTBUG-84867
Change-Id: I12f5e95d8200cfffa5653b6aa566a625f8320ca8
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
2020-08-26 16:37:43 +02:00
Andrei Golubev
b3c1093751 Introduce swap functions for QPromise/QFutureInterface
Made QPromise::swap public, added free standing swap() for
QFutureInterface and QPromise. Updated QPromise special member
functions. Extended tests

Task-number: QTBUG-84977
Change-Id: I5daf6876df306d082441dbcdf5ae4dee3bfc0ead
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
2020-08-03 16:47:31 +02:00
Andrei Golubev
385f0732d9 Add QPromise implementation
QPromise and QFuture created from it share the same internal state
(namely, QFutureInterface object). QPromise provides high-level
management of the shared resource, ensuring thread-safe behavior
on construction and destruction (also taking into account
QFuture::waitForFinished() semantics).

QFuture acts as a primary controller of QPromise via action
initiating methods such as suspend() or cancel(). QPromise is
equipped with methods to check the status, but the actual
handling of QFuture action "requests" is user-defined.

[ChangeLog][QtCore][QPromise] Added QPromise class to accompany
QFuture. It allows one to communicate computation results and
progress to the QFuture via a shared state.

Task-number: QTBUG-81586
Change-Id: Ibab9681d35fe63754bf394ad0e7923e2683e2457
Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
2020-06-09 17:21:38 +03:00