1// Copyright (C) 2021 The Qt Company Ltd.
2// Copyright (C) 2021 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QAPPLICATIONSTATIC_H
6#define QAPPLICATIONSTATIC_H
7
8#include <QtCore/QMutex>
9#include <QtCore/qcoreapplication.h>
10#include <QtCore/qglobalstatic.h>
11
12#include <new>
13
14QT_BEGIN_NAMESPACE
15
16namespace QtGlobalStatic {
17template <typename QAS> struct ApplicationHolder
18{
19 using Type = typename QAS::QAS_Type;
20 using PlainType = std::remove_cv_t<Type>;
21
22 Q_CONSTINIT static inline struct { alignas(Type) unsigned char data[sizeof(Type)]; } storage = {};
23 Q_CONSTINIT static inline QBasicAtomicInteger<qint8> guard = { QtGlobalStatic::Uninitialized };
24 Q_CONSTINIT static inline QBasicMutex mutex {};
25
26 static constexpr bool MutexLockIsNoexcept = noexcept(mutex.lock());
27 static constexpr bool ConstructionIsNoexcept = noexcept(QAS::innerFunction(nullptr));
28
29 ApplicationHolder() = default;
30 Q_DISABLE_COPY_MOVE(ApplicationHolder)
31 ~ApplicationHolder()
32 {
33 if (guard.loadAcquire() == QtGlobalStatic::Initialized) {
34 // No mutex! Up to external code to ensure no race happens.
35 guard.storeRelease(newValue: QtGlobalStatic::Destroyed);
36 realPointer()->~PlainType();
37 }
38 }
39
40 static PlainType *realPointer()
41 {
42 return std::launder(reinterpret_cast<PlainType *>(&storage));
43 }
44
45 // called from QGlobalStatic::instance()
46 PlainType *pointer() noexcept(MutexLockIsNoexcept && ConstructionIsNoexcept)
47 {
48 if (guard.loadAcquire() == QtGlobalStatic::Initialized)
49 return realPointer();
50 QMutexLocker locker(&mutex);
51 if (guard.loadRelaxed() == QtGlobalStatic::Uninitialized) {
52 QAS::innerFunction(&storage);
53 QObject::connect(QCoreApplication::instance(), &QObject::destroyed, reset);
54 guard.storeRelease(newValue: QtGlobalStatic::Initialized);
55 }
56 return realPointer();
57 }
58
59 static void reset()
60 {
61 // we only synchronize using the mutex here, not the guard
62 QMutexLocker locker(&mutex);
63 realPointer()->~PlainType();
64 guard.storeRelaxed(newValue: QtGlobalStatic::Uninitialized);
65 }
66};
67} // namespace QtGlobalStatic
68
69#define Q_APPLICATION_STATIC(TYPE, NAME, ...) \
70 namespace { struct Q_QAS_ ## NAME { \
71 typedef TYPE QAS_Type; \
72 static void innerFunction(void *pointer) \
73 noexcept(noexcept(std::remove_cv_t<QAS_Type>(__VA_ARGS__))) \
74 { \
75 new (pointer) QAS_Type(__VA_ARGS__); \
76 } \
77 }; } \
78 static QGlobalStatic<QtGlobalStatic::ApplicationHolder<Q_QAS_ ## NAME>> NAME;\
79 /**/
80
81QT_END_NAMESPACE
82
83#endif // QAPPLICATIONSTATIC_H
84

source code of qtbase/src/corelib/kernel/qapplicationstatic.h