From f7eff7251786186ca895c8fc537b304bc89977b3 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 24 Feb 2012 18:44:17 +0100 Subject: Add a new Q_GLOBAL_STATIC implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unlike the previous implementation, this implementation is locked: only one initialisation is ever run at the same time. It is exception-safe, meaning that a throwing constructor will restart the process. Also, start using the thread-safe behaviour that GCC has offered for a long time and C++11 requires. Change-Id: I20db44f57d258923df64c0051358fd0d9a5ccd51 Reviewed-by: Olivier Goffart Reviewed-by: David Faure (KDE) Reviewed-by: Jędrzej Nowacki --- src/corelib/global/qglobalstatic.h | 157 +++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 src/corelib/global/qglobalstatic.h (limited to 'src/corelib/global/qglobalstatic.h') diff --git a/src/corelib/global/qglobalstatic.h b/src/corelib/global/qglobalstatic.h new file mode 100644 index 0000000000..78a4acff12 --- /dev/null +++ b/src/corelib/global/qglobalstatic.h @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Intel Corporation +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#ifndef QGLOBALSTATIC_H +#define QGLOBALSTATIC_H + +#include + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +/* + * QGlobalStatic internals: + * + * The pointer is initialized to 0. + * The guard is initialized to 0. + * The guard can assume the following values: + * -2: object initialized and already destroyed + * -1: object initialized and is still valid + * 0: not initialized, the value of the pointer should be null + * +1: initializing, must wait until a state change happens + * (not used in the current implementation) + */ + +namespace QtGlobalStatic { +enum GuardValues { + Destroyed = -2, + Initialized = -1, + Uninitialized = 0, + Initializing = 1 +}; +} + +#if defined(QT_NO_THREAD) || defined(Q_CC_GNU) +// some compilers support thread-safe statics +// The IA-64 C++ ABI requires this, so we know that all GCC versions since 3.4 +// support it. C++11 also requires this behavior. +// Clang and Intel CC masquerade as GCC when compiling on Linux and Mac OS X. + +#define Q_GLOBAL_STATIC_INTERNAL(ARGS) \ + Q_DECL_HIDDEN inline Type *innerFunction() \ + { \ + struct HolderBase { \ + ~HolderBase() Q_DECL_NOTHROW \ + { guard.store(QtGlobalStatic::Destroyed); } \ + }; \ + static struct Holder : public HolderBase { \ + Type value; \ + Holder() \ + Q_DECL_NOEXCEPT_EXPR(noexcept(Type ARGS)) \ + : value ARGS \ + { guard.store(QtGlobalStatic::Initialized); } \ + } holder; \ + return &holder.value; \ + } +#else +// We don't know if this compiler supports thread-safe global statics +// so use our own locked implementation + +QT_END_NAMESPACE +#include +QT_BEGIN_NAMESPACE + +#define Q_GLOBAL_STATIC_INTERNAL(ARGS) \ + Q_DECL_HIDDEN inline Type *innerFunction() \ + { \ + static Type *d; \ + static QBasicMutex mutex; \ + int x = guard.loadAcquire(); \ + if (Q_UNLIKELY(x >= QtGlobalStatic::Uninitialized)) { \ + QMutexLocker locker(&mutex); \ + if (guard.load() == QtGlobalStatic::Uninitialized) { \ + d = new Type ARGS; \ + static struct Cleanup { \ + ~Cleanup() { \ + delete d; \ + guard.store(QtGlobalStatic::Destroyed); \ + } \ + } cleanup; \ + guard.store(QtGlobalStatic::Initialized); \ + } \ + } \ + return d; \ + } +#endif + +// this class must be POD, unless the compiler supports thread-safe statics +template +struct QGlobalStatic +{ + typedef T Type; + + bool isDestroyed() const { return guard.load() <= QtGlobalStatic::Destroyed; } + bool exists() const { return guard.load() == QtGlobalStatic::Initialized; } + operator Type *() { if (isDestroyed()) return 0; return innerFunction(); } + Type *operator()() { if (isDestroyed()) return 0; return innerFunction(); } + Type *operator->() { return innerFunction(); } + Type &operator*() { return *innerFunction(); } +}; + +#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \ + namespace { namespace Q_QGS_ ## NAME { \ + typedef TYPE Type; \ + QBasicAtomicInt guard = Q_BASIC_ATOMIC_INITIALIZER(QtGlobalStatic::Uninitialized); \ + Q_GLOBAL_STATIC_INTERNAL(ARGS) \ + } } \ + static QGlobalStatic NAME; + +#define Q_GLOBAL_STATIC(TYPE, NAME) \ + Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ()) + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QGLOBALSTATIC_H -- cgit v1.2.3 From c0860d26a1b87f42842faeda3e6043a775916594 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 22 Jan 2013 18:26:25 -0800 Subject: Doc: write up the docs for Q_GLOBAL_STATIC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I5bf4d0d027dc8f960c94b4be3ebf7381e9ef4be1 Reviewed-by: Jędrzej Nowacki Reviewed-by: Olivier Goffart --- src/corelib/global/qglobalstatic.h | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'src/corelib/global/qglobalstatic.h') diff --git a/src/corelib/global/qglobalstatic.h b/src/corelib/global/qglobalstatic.h index 78a4acff12..487b0dfdb4 100644 --- a/src/corelib/global/qglobalstatic.h +++ b/src/corelib/global/qglobalstatic.h @@ -49,19 +49,6 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -/* - * QGlobalStatic internals: - * - * The pointer is initialized to 0. - * The guard is initialized to 0. - * The guard can assume the following values: - * -2: object initialized and already destroyed - * -1: object initialized and is still valid - * 0: not initialized, the value of the pointer should be null - * +1: initializing, must wait until a state change happens - * (not used in the current implementation) - */ - namespace QtGlobalStatic { enum GuardValues { Destroyed = -2, -- cgit v1.2.3 From 07e3bcdc106ac42703ae0fb88b6cac2d2bfdd072 Mon Sep 17 00:00:00 2001 From: Sergio Ahumada Date: Sat, 26 Jan 2013 21:42:12 +0100 Subject: Remove QT_{BEGIN,END}_HEADER macro usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The macro was made empty in ba3dc5f3b56d1fab6fe37fe7ae08096d7dc68bcb and is no longer necessary or used. Discussed-on: http://lists.qt-project.org/pipermail/development/2013-January/009284.html Change-Id: Id2bb2e2cabde059305d4af5f12593344ba30f001 Reviewed-by: Laszlo Papp Reviewed-by: Jędrzej Nowacki Reviewed-by: hjk --- src/corelib/global/qglobalstatic.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/corelib/global/qglobalstatic.h') diff --git a/src/corelib/global/qglobalstatic.h b/src/corelib/global/qglobalstatic.h index 487b0dfdb4..336512eac3 100644 --- a/src/corelib/global/qglobalstatic.h +++ b/src/corelib/global/qglobalstatic.h @@ -46,7 +46,6 @@ #include -QT_BEGIN_HEADER QT_BEGIN_NAMESPACE namespace QtGlobalStatic { @@ -139,6 +138,4 @@ struct QGlobalStatic Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ()) QT_END_NAMESPACE -QT_END_HEADER - #endif // QGLOBALSTATIC_H -- cgit v1.2.3 From 50d3a2917e37cd173f373a83542314002b2ab6c7 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 27 Feb 2013 15:48:17 -0800 Subject: Fix Q_GLOBAL_STATIC support for exceptions The problem was that the HolderBase destructor was getting called after the contained type's constructor threw an exception, as is required by RAII semantics (the base was fully initialized, so it had to be destroyed). That was required because we want to return a non-null pointer from operator() during destruction and return null after destruction, to keep compatibility with Qt 4. The solution is to only set the guard to Destroyed only if it is already at value Initialized. This way, if the HolderBase destructor is run as part of the stack unwinding, it knows that the construction did not complete. Change-Id: I9849b43ed7112bf9e70861b48a56a924c286617e Reviewed-by: Olivier Goffart --- src/corelib/global/qglobalstatic.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/corelib/global/qglobalstatic.h') diff --git a/src/corelib/global/qglobalstatic.h b/src/corelib/global/qglobalstatic.h index 336512eac3..a6268e057e 100644 --- a/src/corelib/global/qglobalstatic.h +++ b/src/corelib/global/qglobalstatic.h @@ -68,7 +68,8 @@ enum GuardValues { { \ struct HolderBase { \ ~HolderBase() Q_DECL_NOTHROW \ - { guard.store(QtGlobalStatic::Destroyed); } \ + { if (guard.load() == QtGlobalStatic::Initialized) \ + guard.store(QtGlobalStatic::Destroyed); } \ }; \ static struct Holder : public HolderBase { \ Type value; \ -- cgit v1.2.3