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
47#include <type_traits>
48
49QT_BEGIN_NAMESPACE
50
51namespace QtGlobalStatic {
52enum GuardValues {
53 Destroyed = -2,
54 Initialized = -1,
55 Uninitialized = 0,
56 Initializing = 1
57};
58}
59
60#if !QT_CONFIG(thread) || defined(Q_COMPILER_THREADSAFE_STATICS)
61// some compilers support thread-safe statics
62// The IA-64 C++ ABI requires this, so we know that all GCC versions since 3.4
63// support it. C++11 also requires this behavior.
64// Clang and Intel CC masquerade as GCC when compiling on Linux.
65//
66// Apple's libc++abi however uses a global lock for initializing local statics,
67// which will block other threads also trying to initialize a local static
68// until the constructor returns ...
69// We better avoid these kind of problems by using our own locked implementation.
70
71#if defined(Q_OS_UNIX) && defined(Q_CC_INTEL)
72// Work around Intel issue ID 6000058488:
73// local statics inside an inline function inside an anonymous namespace are global
74// symbols (this affects the IA-64 C++ ABI, so OS X and Linux only)
75# define Q_GLOBAL_STATIC_INTERNAL_DECORATION Q_DECL_HIDDEN
76#else
77# define Q_GLOBAL_STATIC_INTERNAL_DECORATION Q_DECL_HIDDEN inline
78#endif
79
80#define Q_GLOBAL_STATIC_INTERNAL(ARGS) \
81 Q_GLOBAL_STATIC_INTERNAL_DECORATION Type *innerFunction() \
82 { \
83 struct HolderBase { \
84 ~HolderBase() noexcept \
85 { if (guard.loadRelaxed() == QtGlobalStatic::Initialized) \
86 guard.storeRelaxed(QtGlobalStatic::Destroyed); } \
87 }; \
88 static struct Holder : public HolderBase { \
89 Type value; \
90 Holder() \
91 noexcept(noexcept(typename std::remove_cv<Type>::type ARGS)) \
92 : value ARGS \
93 { guard.storeRelaxed(QtGlobalStatic::Initialized); } \
94 } holder; \
95 return &holder.value; \
96 }
97#else
98// We don't know if this compiler supports thread-safe global statics
99// so use our own locked implementation
100
101QT_END_NAMESPACE
102#include <QtCore/qmutex.h>
103#include <mutex>
104QT_BEGIN_NAMESPACE
105
106#define Q_GLOBAL_STATIC_INTERNAL(ARGS) \
107 Q_DECL_HIDDEN inline Type *innerFunction() \
108 { \
109 static Type *d; \
110 static QBasicMutex mutex; \
111 int x = guard.loadAcquire(); \
112 if (Q_UNLIKELY(x >= QtGlobalStatic::Uninitialized)) { \
113 const std::lock_guard<QBasicMutex> locker(mutex); \
114 if (guard.loadRelaxed() == QtGlobalStatic::Uninitialized) { \
115 d = new Type ARGS; \
116 static struct Cleanup { \
117 ~Cleanup() { \
118 delete d; \
119 guard.storeRelaxed(QtGlobalStatic::Destroyed); \
120 } \
121 } cleanup; \
122 guard.storeRelease(QtGlobalStatic::Initialized); \
123 } \
124 } \
125 return d; \
126 }
127#endif
128
129// this class must be POD, unless the compiler supports thread-safe statics
130template <typename T, T *(&innerFunction)(), QBasicAtomicInt &guard>
131struct QGlobalStatic
132{
133 typedef T Type;
134
135 bool isDestroyed() const { return guard.loadRelaxed() <= QtGlobalStatic::Destroyed; }
136 bool exists() const { return guard.loadRelaxed() == QtGlobalStatic::Initialized; }
137 operator Type *() { if (isDestroyed()) return nullptr; return innerFunction(); }
138 Type *operator()() { if (isDestroyed()) return nullptr; return innerFunction(); }
139 Type *operator->()
140 {
141 Q_ASSERT_X(!isDestroyed(), "Q_GLOBAL_STATIC", "The global static was used after being destroyed");
142 return innerFunction();
143 }
144 Type &operator*()
145 {
146 Q_ASSERT_X(!isDestroyed(), "Q_GLOBAL_STATIC", "The global static was used after being destroyed");
147 return *innerFunction();
148 }
149};
150
151#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \
152 namespace { namespace Q_QGS_ ## NAME { \
153 typedef TYPE Type; \
154 QBasicAtomicInt guard = Q_BASIC_ATOMIC_INITIALIZER(QtGlobalStatic::Uninitialized); \
155 Q_GLOBAL_STATIC_INTERNAL(ARGS) \
156 } } \
157 static QGlobalStatic<TYPE, \
158 Q_QGS_ ## NAME::innerFunction, \
159 Q_QGS_ ## NAME::guard> NAME;
160
161#define Q_GLOBAL_STATIC(TYPE, NAME) \
162 Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ())
163
164QT_END_NAMESPACE
165#endif // QGLOBALSTATIC_H
166