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() Q_DECL_NOTHROW \
83 { if (guard.load() == QtGlobalStatic::Initialized) \
84 guard.store(QtGlobalStatic::Destroyed); } \
85 }; \
86 static struct Holder : public HolderBase { \
87 Type value; \
88 Holder() \
89 Q_DECL_NOEXCEPT_EXPR(noexcept(Type ARGS)) \
90 : value ARGS \
91 { guard.store(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>
101QT_BEGIN_NAMESPACE
102
103#define Q_GLOBAL_STATIC_INTERNAL(ARGS) \
104 Q_DECL_HIDDEN inline Type *innerFunction() \
105 { \
106 static Type *d; \
107 static QBasicMutex mutex; \
108 int x = guard.loadAcquire(); \
109 if (Q_UNLIKELY(x >= QtGlobalStatic::Uninitialized)) { \
110 QMutexLocker locker(&mutex); \
111 if (guard.load() == QtGlobalStatic::Uninitialized) { \
112 d = new Type ARGS; \
113 static struct Cleanup { \
114 ~Cleanup() { \
115 delete d; \
116 guard.store(QtGlobalStatic::Destroyed); \
117 } \
118 } cleanup; \
119 guard.storeRelease(QtGlobalStatic::Initialized); \
120 } \
121 } \
122 return d; \
123 }
124#endif
125
126// this class must be POD, unless the compiler supports thread-safe statics
127template <typename T, T *(&innerFunction)(), QBasicAtomicInt &guard>
128struct QGlobalStatic
129{
130 typedef T Type;
131
132 bool isDestroyed() const { return guard.load() <= QtGlobalStatic::Destroyed; }
133 bool exists() const { return guard.load() == QtGlobalStatic::Initialized; }
134 operator Type *() { if (isDestroyed()) return 0; return innerFunction(); }
135 Type *operator()() { if (isDestroyed()) return 0; return innerFunction(); }
136 Type *operator->()
137 {
138 Q_ASSERT_X(!isDestroyed(), "Q_GLOBAL_STATIC", "The global static was used after being destroyed");
139 return innerFunction();
140 }
141 Type &operator*()
142 {
143 Q_ASSERT_X(!isDestroyed(), "Q_GLOBAL_STATIC", "The global static was used after being destroyed");
144 return *innerFunction();
145 }
146};
147
148#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \
149 namespace { namespace Q_QGS_ ## NAME { \
150 typedef TYPE Type; \
151 QBasicAtomicInt guard = Q_BASIC_ATOMIC_INITIALIZER(QtGlobalStatic::Uninitialized); \
152 Q_GLOBAL_STATIC_INTERNAL(ARGS) \
153 } } \
154 static QGlobalStatic<TYPE, \
155 Q_QGS_ ## NAME::innerFunction, \
156 Q_QGS_ ## NAME::guard> NAME;
157
158#define Q_GLOBAL_STATIC(TYPE, NAME) \
159 Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ())
160
161QT_END_NAMESPACE
162#endif // QGLOBALSTATIC_H
163