1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
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 General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29
30#include "qplatformdefs.h"
31#include "qthreadonce.h"
32
33#include "qmutex.h"
34
35Q_GLOBAL_STATIC(QRecursiveMutex, onceInitializationMutex)
36
37enum QOnceExtra {
38 MustRunCode = 0x01,
39 MustUnlockMutex = 0x02
40};
41
42/*!
43 \internal
44 Initialize the Q_ONCE structure.
45
46 Q_ONCE consists of two variables:
47 - a static POD QOnceControl::ControlVariable (it's a QBasicAtomicInt)
48 - an automatic QOnceControl that controls the former
49
50 The POD is initialized to 0.
51
52 When QOnceControl's constructor starts, it'll lock the global
53 initialization mutex. It'll then check if it's the first to up
54 the control variable and will take note.
55
56 The QOnceControl's destructor will unlock the global
57 initialization mutex.
58*/
59QOnceControl::QOnceControl(QBasicAtomicInt *control)
60{
61 d = 0;
62 gv = control;
63 // check if code has already run once
64 if (gv->loadAcquire() == 2) {
65 // uncontended case: it has already initialized
66 // no waiting
67 return;
68 }
69
70 // acquire the path
71 onceInitializationMutex()->lock();
72 extra = MustUnlockMutex;
73
74 if (gv->testAndSetAcquire(expectedValue: 0, newValue: 1)) {
75 // path acquired, we're the first
76 extra |= MustRunCode;
77 }
78}
79
80QOnceControl::~QOnceControl()
81{
82 if (mustRunCode())
83 // code wasn't run!
84 gv->testAndSetRelease(expectedValue: 1, newValue: 0);
85 else
86 gv->testAndSetRelease(expectedValue: 1, newValue: 2);
87 if (extra & MustUnlockMutex)
88 onceInitializationMutex()->unlock();
89}
90
91/*!
92 \internal
93 Returns true if the initialization code must be run.
94
95 Obviously, the initialization code must be run only once...
96*/
97bool QOnceControl::mustRunCode()
98{
99 return extra & MustRunCode;
100}
101
102void QOnceControl::done()
103{
104 extra &= ~MustRunCode;
105}
106

source code of qtbase/tests/auto/corelib/thread/qthreadonce/qthreadonce.cpp