forked from hexagon-geo-surv/qtbase
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Long live QAtomicScopedValueRollback (private API)!
QScopedValueRollback has a few users that apply it on QAtomicInt, which happens to work as QAtomicInt is copy-constructible and its ctors are implicit. But that's of course nonsense. We don't need to store the oldValue in an atomic, nor do we need to pass the new value into the ctor as an atomic. So, add a QAtomicScopedValueRollback which works on std::atomic as well as the Qt atomics, but distinguishes between the reference (which is atomic) and the value (which isn't), and use it in one of the users, tst_QList. Keep it private until we know whether there's an actual need for this. The test is a copy of tst_qscopedvaluefallback, so the occasional oddity (like atomic op*=) should be ignored. Task-number: QTBUG-103835 Change-Id: I3c05b3e51f465698657a02ca5521ed465386e9a6 Reviewed-by: Qt CI Bot <[email protected]> Reviewed-by: Fabian Kosmale <[email protected]>
- Loading branch information
Showing
7 changed files
with
265 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// Copyright (C) 2022 The Qt Company Ltd. | ||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only | ||
|
||
#ifndef QATOMICSCOPEDVALUEROLLBACK_P_H | ||
#define QATOMICSCOPEDVALUEROLLBACK_P_H | ||
|
||
#include <QtCore/qglobal.h> | ||
#include <QtCore/qatomic.h> | ||
|
||
#include <atomic> | ||
|
||
QT_BEGIN_NAMESPACE | ||
|
||
template <typename T> | ||
class [[nodiscard]] QAtomicScopedValueRollback | ||
{ | ||
std::atomic<T> &m_atomic; | ||
T m_value; | ||
std::memory_order m_mo; | ||
|
||
Q_DISABLE_COPY_MOVE(QAtomicScopedValueRollback) | ||
|
||
constexpr std::memory_order store_part(std::memory_order mo) noexcept | ||
{ | ||
switch (mo) { | ||
case std::memory_order_relaxed: | ||
case std::memory_order_consume: | ||
case std::memory_order_acquire: return std::memory_order_relaxed; | ||
case std::memory_order_release: | ||
case std::memory_order_acq_rel: return std::memory_order_release; | ||
case std::memory_order_seq_cst: return std::memory_order_seq_cst; | ||
} | ||
// GCC 8.x does not tread __builtin_unreachable() as constexpr | ||
#if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900) | ||
Q_UNREACHABLE(); | ||
#endif | ||
return std::memory_order_seq_cst; | ||
} | ||
public: | ||
// | ||
// std::atomic: | ||
// | ||
explicit constexpr | ||
QAtomicScopedValueRollback(std::atomic<T> &var, | ||
std::memory_order mo = std::memory_order_seq_cst) | ||
: m_atomic(var), m_value(var.load(mo)), m_mo(mo) {} | ||
|
||
explicit constexpr | ||
QAtomicScopedValueRollback(std::atomic<T> &var, T value, | ||
std::memory_order mo = std::memory_order_seq_cst) | ||
: m_atomic(var), m_value(var.exchange(value, mo)), m_mo(mo) {} | ||
|
||
// | ||
// Q(Basic)AtomicInteger: | ||
// | ||
explicit constexpr | ||
QAtomicScopedValueRollback(QBasicAtomicInteger<T> &var, | ||
std::memory_order mo = std::memory_order_seq_cst) | ||
: QAtomicScopedValueRollback(var._q_value, mo) {} | ||
|
||
explicit constexpr | ||
QAtomicScopedValueRollback(QBasicAtomicInteger<T> &var, T value, | ||
std::memory_order mo = std::memory_order_seq_cst) | ||
: QAtomicScopedValueRollback(var._q_value, value, mo) {} | ||
|
||
// | ||
// Q(Basic)AtomicPointer: | ||
// | ||
explicit constexpr | ||
QAtomicScopedValueRollback(QBasicAtomicPointer<std::remove_pointer_t<T>> &var, | ||
std::memory_order mo = std::memory_order_seq_cst) | ||
: QAtomicScopedValueRollback(var._q_value, mo) {} | ||
|
||
explicit constexpr | ||
QAtomicScopedValueRollback(QBasicAtomicPointer<std::remove_pointer_t<T>> &var, T value, | ||
std::memory_order mo = std::memory_order_seq_cst) | ||
: QAtomicScopedValueRollback(var._q_value, value, mo) {} | ||
|
||
#if __cpp_constexpr >= 201907L | ||
constexpr | ||
#endif | ||
~QAtomicScopedValueRollback() | ||
{ | ||
m_atomic.store(m_value, store_part(m_mo)); | ||
} | ||
|
||
constexpr void commit() | ||
{ | ||
m_value = m_atomic.load(m_mo); | ||
} | ||
}; | ||
|
||
QT_END_NAMESPACE | ||
|
||
#endif // QATOMICASCOPEDVALUEROLLBACK_P_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 6 additions & 0 deletions
6
tests/auto/corelib/tools/qatomicscopedvaluerollback/CMakeLists.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
qt_internal_add_test(tst_qatomicscopedvaluerollback | ||
SOURCES | ||
tst_qatomicscopedvaluerollback.cpp | ||
PUBLIC_LIBRARIES | ||
Qt::CorePrivate | ||
) |
157 changes: 157 additions & 0 deletions
157
tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
// Copyright (C) 2022 The Qt Company Ltd. | ||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 | ||
|
||
#include <QtCore/private/qatomicscopedvaluerollback_p.h> | ||
|
||
#include <QTest> | ||
|
||
class tst_QAtomicScopedValueRollback : public QObject | ||
{ | ||
Q_OBJECT | ||
|
||
private Q_SLOTS: | ||
void leavingScope(); | ||
void leavingScopeAfterCommit(); | ||
void rollbackToPreviousCommit(); | ||
void exceptions(); | ||
void earlyExitScope(); | ||
private: | ||
void earlyExitScope_helper(int exitpoint, std::atomic<int> &member); | ||
}; | ||
|
||
void tst_QAtomicScopedValueRollback::leavingScope() | ||
{ | ||
QAtomicInt i = 0; | ||
QBasicAtomicInteger<bool> b = false; | ||
std::atomic<bool> b2 = false; | ||
|
||
//test rollback on going out of scope | ||
{ | ||
QAtomicScopedValueRollback ri(i); | ||
QAtomicScopedValueRollback rb(b); | ||
QAtomicScopedValueRollback rb2(b2, true); | ||
QCOMPARE(b.loadRelaxed(), false); | ||
QCOMPARE(b2, true); | ||
QCOMPARE(i.loadRelaxed(), 0); | ||
b.storeRelaxed(true); | ||
i.storeRelaxed(1); | ||
QCOMPARE(b.loadRelaxed(), true); | ||
QCOMPARE(i.loadRelaxed(), 1); | ||
} | ||
QCOMPARE(b.loadRelaxed(), false); | ||
QCOMPARE(b2, false); | ||
QCOMPARE(i.loadRelaxed(), 0); | ||
} | ||
|
||
void tst_QAtomicScopedValueRollback::leavingScopeAfterCommit() | ||
{ | ||
std::atomic<int> i = 0; | ||
QAtomicInteger<bool> b = false; | ||
|
||
//test rollback on going out of scope | ||
{ | ||
QAtomicScopedValueRollback ri(i); | ||
QAtomicScopedValueRollback rb(b); | ||
QCOMPARE(b.loadRelaxed(), false); | ||
QCOMPARE(i, 0); | ||
b.storeRelaxed(true); | ||
i = 1; | ||
QCOMPARE(b.loadRelaxed(), true); | ||
QCOMPARE(i, 1); | ||
ri.commit(); | ||
rb.commit(); | ||
} | ||
QCOMPARE(b.loadRelaxed(), true); | ||
QCOMPARE(i, 1); | ||
} | ||
|
||
void tst_QAtomicScopedValueRollback::rollbackToPreviousCommit() | ||
{ | ||
QBasicAtomicInt i = 0; | ||
{ | ||
QAtomicScopedValueRollback ri(i); | ||
i++; | ||
ri.commit(); | ||
i++; | ||
} | ||
QCOMPARE(i.loadRelaxed(), 1); | ||
{ | ||
QAtomicScopedValueRollback ri1(i); | ||
i++; | ||
ri1.commit(); | ||
i++; | ||
ri1.commit(); | ||
i++; | ||
} | ||
QCOMPARE(i.loadRelaxed(), 3); | ||
} | ||
|
||
void tst_QAtomicScopedValueRollback::exceptions() | ||
{ | ||
std::atomic<bool> b = false; | ||
bool caught = false; | ||
QT_TRY | ||
{ | ||
QAtomicScopedValueRollback rb(b); | ||
b = true; | ||
QT_THROW(std::bad_alloc()); //if Qt compiled without exceptions this is noop | ||
rb.commit(); //if Qt compiled without exceptions, true is committed | ||
} | ||
QT_CATCH(...) | ||
{ | ||
caught = true; | ||
} | ||
QCOMPARE(b, !caught); //expect false if exception was thrown, true otherwise | ||
} | ||
|
||
void tst_QAtomicScopedValueRollback::earlyExitScope() | ||
{ | ||
QAtomicInt ai = 0; | ||
std::atomic<int> aj = 0; | ||
while (true) { | ||
QAtomicScopedValueRollback ri(ai); | ||
++ai; | ||
aj = ai.loadRelaxed(); | ||
if (ai.loadRelaxed() > 8) break; | ||
ri.commit(); | ||
} | ||
QCOMPARE(ai.loadRelaxed(), 8); | ||
QCOMPARE(aj.load(), 9); | ||
|
||
for (int i = 0; i < 5; ++i) { | ||
aj = 1; | ||
earlyExitScope_helper(i, aj); | ||
QCOMPARE(aj.load(), 1 << i); | ||
} | ||
} | ||
|
||
static void operator*=(std::atomic<int> &lhs, int rhs) | ||
{ | ||
int expected = lhs.load(); | ||
while (!lhs.compare_exchange_weak(expected, expected * rhs)) | ||
; | ||
} | ||
|
||
void tst_QAtomicScopedValueRollback::earlyExitScope_helper(int exitpoint, std::atomic<int>& member) | ||
{ | ||
QAtomicScopedValueRollback r(member); | ||
member *= 2; | ||
if (exitpoint == 0) | ||
return; | ||
r.commit(); | ||
member *= 2; | ||
if (exitpoint == 1) | ||
return; | ||
r.commit(); | ||
member *= 2; | ||
if (exitpoint == 2) | ||
return; | ||
r.commit(); | ||
member *= 2; | ||
if (exitpoint == 3) | ||
return; | ||
r.commit(); | ||
} | ||
|
||
QTEST_MAIN(tst_QAtomicScopedValueRollback) | ||
#include "tst_qatomicscopedvaluerollback.moc" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,8 @@ | |
qt_internal_add_test(tst_qlist | ||
SOURCES | ||
tst_qlist.cpp | ||
PUBLIC_LIBRARIES | ||
Qt::CorePrivate | ||
) | ||
|
||
## Scopes: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters