1/****************************************************************************
2**
3** Copyright (C) 2016 Intel Corporation.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <QtCore/qglobal.h>
41
42#ifndef QGLOBALSTATIC_H
43#define QGLOBALSTATIC_H
44
45#include <QtCore/qatomic.h>
46
47QT_BEGIN_NAMESPACE
48
49namespace QtGlobalStatic {
50enum GuardValues {
51 Destroyed = -2,
52 Initialized = -1,
53 Uninitialized = 0,
54 Initializing = 1
55};
56}
57
58#if !QT_CONFIG(thread) || defined(Q_COMPILER_THREADSAFE_STATICS)
59// some compilers support thread-safe statics
60// The IA-64 C++ ABI requires this, so we know that all GCC versions since 3.4
61// support it. C++11 also requires this behavior.
62// Clang and Intel CC masquerade as GCC when compiling on Linux.
63//
64// Apple's libc++abi however uses a global lock for initializing local statics,
65// which will block other threads also trying to initialize a local static
66// until the constructor returns ...
67// We better avoid these kind of problems by using our own locked implementation.
68
69#if defined(Q_OS_UNIX) && defined(Q_CC_INTEL)
70// Work around Intel issue ID 6000058488:
71// local statics inside an inline function inside an anonymous namespace are global
72// symbols (this affects the IA-64 C++ ABI, so OS X and Linux only)
73# define Q_GLOBAL_STATIC_INTERNAL_DECORATION Q_DECL_HIDDEN
74#else
75# define Q_GLOBAL_STATIC_INTERNAL_DECORATION Q_DECL_HIDDEN inline
76#endif
77
78#define Q_GLOBAL_STATIC_INTERNAL(ARGS) \
79 Q_GLOBAL_STATIC_INTERNAL_DECORATION Type *innerFunction() \
80 { \
81 struct HolderBase { \
82 ~HolderBase() noexcept \
83 { if (guard.loadRelaxed() == QtGlobalStatic::Initialized) \
84 guard.storeRelaxed(QtGlobalStatic::Destroyed); } \
85 }; \
86 static struct Holder : public HolderBase { \
87 Type value; \
88 Holder() \
89 noexcept(noexcept(Type ARGS)) \
90 : value ARGS \
91 { guard.storeRelaxed(QtGlobalStatic::Initialized); } \
92 } holder; \
93 return &holder.value; \
94 }
95#else
96// We don't know if this compiler supports thread-safe global statics
97// so use our own locked implementation
98
99QT_END_NAMESPACE
100#include <QtCore/qmutex.h>
101#include <mutex>
102QT_BEGIN_NAMESPACE
103
104#define Q_GLOBAL_STATIC_INTERNAL(ARGS) \
105 Q_DECL_HIDDEN inline Type *innerFunction() \
106 { \
107 static Type *d; \
108 static QBasicMutex mutex; \
109 int x = guard.loadAcquire(); \
110 if (Q_UNLIKELY(x >= QtGlobalStatic::Uninitialized)) { \
111 const std::lock_guard<QBasicMutex> locker(mutex); \
112 if (guard.loadRelaxed() == QtGlobalStatic::Uninitialized) { \
113 d = new Type ARGS; \
114 static struct Cleanup { \
115 ~Cleanup() { \
116 delete d; \
117 guard.storeRelaxed(QtGlobalStatic::Destroyed); \
118 } \
119 } cleanup; \
120 guard.storeRelease(QtGlobalStatic::Initialized); \
121 } \
122 } \
123 return d; \
124 }
125#endif
126
127// this class must be POD, unless the compiler supports thread-safe statics
128template <typename T, T *(&innerFunction)(), QBasicAtomicInt &guard>
129struct QGlobalStatic
130{
131 typedef T Type;
132
133 bool isDestroyed() const { return guard.loadRelaxed() <= QtGlobalStatic::Destroyed; }
134 bool exists() const { return guard.loadRelaxed() == QtGlobalStatic::Initialized; }
135 operator Type *() { if (isDestroyed()) return nullptr; return innerFunction(); }
136 Type *operator()() { if (isDestroyed()) return nullptr; return innerFunction(); }
137 Type *operator->()
138 {
139 Q_ASSERT_X(!isDestroyed(), "Q_GLOBAL_STATIC", "The global static was used after being destroyed");
140 return innerFunction();
141 }
142 Type &operator*()
143 {
144 Q_ASSERT_X(!isDestroyed(), "Q_GLOBAL_STATIC", "The global static was used after being destroyed");
145 return *innerFunction();
146 }
147};
148
149#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \
150 namespace { namespace Q_QGS_ ## NAME { \
151 typedef TYPE Type; \
152 QBasicAtomicInt guard = Q_BASIC_ATOMIC_INITIALIZER(QtGlobalStatic::Uninitialized); \
153 Q_GLOBAL_STATIC_INTERNAL(ARGS) \
154 } } \
155 static QGlobalStatic<TYPE, \
156 Q_QGS_ ## NAME::innerFunction, \
157 Q_QGS_ ## NAME::guard> NAME;
158
159#define Q_GLOBAL_STATIC(TYPE, NAME) \
160 Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ())
161
162QT_END_NAMESPACE
163#endif // QGLOBALSTATIC_H
164