QtBase  v6.3.1
tst_qglobalstatic.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 Thiago Macieira <thiago@kde.org>
4 ** Copyright (C) 2016 Intel Corporation.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
26 ** $QT_END_LICENSE$
27 **
28 ****************************************************************************/
29 
30 #include <QtCore/QThread>
31 #include <QTest>
32 #include <QReadWriteLock>
33 
34 #if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
35 #include <sys/resource.h>
36 #endif
37 
38 #include <QtTest/private/qemulationdetector_p.h>
39 
40 class tst_QGlobalStatic : public QObject
41 {
42  Q_OBJECT
43 
44 public Q_SLOTS:
45  void initTestCase();
46 
47 private Q_SLOTS:
48  void beforeInitialization();
49  void api();
50  void constVolatile();
51  void exception();
52  void catchExceptionAndRetry();
53  void threadStressTest();
54  void afterDestruction();
55 };
56 
58 {
59 #if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
60  // The tests create a lot of threads, which require file descriptors. On systems like
61  // OS X low defaults such as 256 as the limit for the number of simultaneously
62  // open files is not sufficient.
63  struct rlimit numFiles;
64  if (getrlimit(RLIMIT_NOFILE, &numFiles) == 0 && numFiles.rlim_cur < 1024) {
65  numFiles.rlim_cur = qMin(rlim_t(1024), numFiles.rlim_max);
66  setrlimit(RLIMIT_NOFILE, &numFiles);
67  }
68 #endif
69 }
70 
71 Q_GLOBAL_STATIC_WITH_ARGS(const int, constInt, (42))
72 Q_GLOBAL_STATIC_WITH_ARGS(volatile int, volatileInt, (-47))
73 
75 {
76  // never called
77  constInt();
78  volatileInt();
79 }
80 
81 // do not initialize the following Q_GLOBAL_STATIC
82 Q_GLOBAL_STATIC(int, checkedBeforeInitialization)
83 void tst_QGlobalStatic::beforeInitialization()
84 {
85  QVERIFY(!checkedBeforeInitialization.exists());
86  QVERIFY(!checkedBeforeInitialization.isDestroyed());
87 }
88 
89 struct Type {
90  int i;
91 };
92 
93 Q_GLOBAL_STATIC(Type, checkedAfterInitialization)
94 void tst_QGlobalStatic::api()
95 {
96  // check the API
97  QVERIFY((Type *)checkedAfterInitialization);
98  QVERIFY(checkedAfterInitialization());
99  *checkedAfterInitialization = Type();
100  *checkedAfterInitialization() = Type();
101 
102  checkedAfterInitialization()->i = 47;
103  checkedAfterInitialization->i = 42;
104  QCOMPARE(checkedAfterInitialization()->i, 42);
105  checkedAfterInitialization()->i = 47;
106  QCOMPARE(checkedAfterInitialization->i, 47);
107 
108  QVERIFY(checkedAfterInitialization.exists());
109  QVERIFY(!checkedAfterInitialization.isDestroyed());
110 }
111 
112 void tst_QGlobalStatic::constVolatile()
113 {
114  QCOMPARE(*constInt(), 42);
115  QCOMPARE((int)*volatileInt(), -47);
116  QCOMPARE(*constInt(), 42);
117  QCOMPARE((int)*volatileInt(), -47);
118 }
119 
121 {
125  {
126  throw 0;
127  }
128 
130  {
132  if (throwControl.fetchAndAddRelaxed(-1) != 0)
133  throw 0;
134  }
136 };
137 
140 
141 Q_GLOBAL_STATIC(ThrowingType, throwingGS)
142 void tst_QGlobalStatic::exception()
143 {
144  bool exceptionCaught = false;
145  try {
146  throwingGS();
147  } catch (int) {
148  exceptionCaught = true;
149  }
150  QVERIFY(exceptionCaught);
152  QVERIFY(!throwingGS.exists());
153  QVERIFY(!throwingGS.isDestroyed());
154 }
155 
158 void tst_QGlobalStatic::catchExceptionAndRetry()
159 {
160  if (exceptionControlVar.loadRelaxed() != 1)
161  QSKIP("This test cannot be run more than once");
164 
165  bool exceptionCaught = false;
166  try {
167  exceptionGS();
168  } catch (int) {
169  exceptionCaught = true;
170  }
171  QCOMPARE(ThrowingType::constructedCount.loadRelaxed(), 1);
172  QVERIFY(exceptionCaught);
173 
174  exceptionGS();
175  QCOMPARE(ThrowingType::constructedCount.loadRelaxed(), 2);
176 }
177 
180 
181 
182 void tst_QGlobalStatic::threadStressTest()
183 {
184  if (QTestPrivate::isRunningArmOnX86())
185  QSKIP("Frequently hangs on QEMU, QTBUG-91423");
186 
187  class ThreadStressTestThread: public QThread
188  {
189  public:
191  void run() override
192  {
193  QReadLocker l(lock);
194  //usleep(QRandomGenerator::global()->generate(200));
195  // thundering herd
196  try {
197  threadStressTestGS();
198  } catch (int) {
199  }
200  }
201  };
202 
205  int expectedConstructionCount = threadStressTestControlVar.loadRelaxed() + 1;
206  if (expectedConstructionCount <= 0)
207  QSKIP("This test cannot be run more than once");
208 
209 #ifdef Q_OS_INTEGRITY
210  // OPEN_REALTIME_THREADS = 123 on current INTEGRITY environment
211  // if try to create more, app is halted
212  const int numThreads = 122;
213 #else
214  const int numThreads = 200;
215 #endif
216  ThreadStressTestThread threads[numThreads];
218  lock.lockForWrite();
219  for (int i = 0; i < numThreads; ++i) {
220  threads[i].lock = &lock;
221  threads[i].start();
222  }
223 
224  // wait for all threads
225  // release the herd
226  lock.unlock();
227 
228  for (int i = 0; i < numThreads; ++i)
229  threads[i].wait();
230 
231  QCOMPARE(ThrowingType::constructedCount.loadAcquire(), expectedConstructionCount);
232  QCOMPARE(ThrowingType::destructedCount.loadAcquire(), 0);
233 }
234 
235 Q_GLOBAL_STATIC(int, checkedAfterDestruction)
236 void tst_QGlobalStatic::afterDestruction()
237 {
238  // this test will not produce results now
239  // it will simply run some code on destruction (after the global statics have been deleted)
240  // if that fails, this will cause a crash
241 
242  // static destruction is LIFO: so we must add our exit-time code before the
243  // global static is used for the first time
244  static struct RunAtExit {
245  ~RunAtExit() {
246  int *ptr = checkedAfterDestruction();
247  if (ptr)
248  qFatal("Global static is not null as was expected");
249  }
250  } runAtExit;
251  (void) runAtExit;
252 
253  *checkedAfterDestruction = 42;
254 }
255 
257 
258 #include "tst_qglobalstatic.moc"
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
bool ref() noexcept
Definition: qbasicatomic.h:101
void storeRelaxed(T newValue) noexcept
Definition: qbasicatomic.h:91
T fetchAndAddRelaxed(T valueToAdd) noexcept
Definition: qbasicatomic.h:140
T loadRelaxed() const noexcept
Definition: qbasicatomic.h:90
The QObject class is the base class of all Qt objects.
Definition: qobject.h:125
The QReadLocker class is a convenience class that simplifies locking and unlocking read-write locks f...
The QReadWriteLock class provides read-write locking.
void unlock() noexcept
void lockForWrite() noexcept
QCOMPARE(spy.count(), 1)
void
Definition: png.h:1080
#define Q_BASIC_ATOMIC_INITIALIZER(a)
#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS)
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qFatal
Definition: qlogging.h:181
#define QSKIP(statement,...)
Definition: qtestcase.h:222
#define QVERIFY(statement)
Definition: qtestcase.h:64
#define Q_OBJECT
Definition: qtmetamacros.h:158
#define Q_SLOTS
Definition: qtmetamacros.h:80
QReadWriteLock lock
[0]
QDBusVariant Type
static QBasicAtomicInt destructedCount
static QBasicAtomicInt constructedCount
ThrowingType(QBasicAtomicInt &throwControl)
Definition: moc.h:48
bool run(const QString &name, QString *errorMessage)
QBasicAtomicInt exceptionControlVar
QBasicAtomicInt threadStressTestControlVar
QTEST_APPLESS_MAIN(tst_QGlobalStatic)
void otherFunction()
QSet< QThread * > threads