thread/qthreadstorage.cpp

Source codeSwitch to Preprocessed file
LineSource CodeCoverage
1/**************************************************************************** -
2** -
3** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -
4** Contact: http://www.qt-project.org/legal -
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 Digia. For licensing terms and -
14** conditions see http://qt.digia.com/licensing. For further information -
15** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software -
20** Foundation and appearing in the file LICENSE.LGPL included in the -
21** packaging of this file. Please review the following information to -
22** ensure the GNU Lesser General Public License version 2.1 requirements -
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -
24** -
25** In addition, as a special exception, Digia gives you certain additional -
26** rights. These rights are described in the Digia Qt LGPL Exception -
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -
28** -
29** GNU General Public License Usage -
30** Alternatively, this file may be used under the terms of the GNU -
31** General Public License version 3.0 as published by the Free Software -
32** Foundation and appearing in the file LICENSE.GPL included in the -
33** packaging of this file. Please review the following information to -
34** ensure the GNU General Public License version 3.0 requirements will be -
35** met: http://www.gnu.org/copyleft/gpl.html. -
36** -
37** -
38** $QT_END_LICENSE$ -
39** -
40****************************************************************************/ -
41 -
42#include "qthreadstorage.h" -
43 -
44#ifndef QT_NO_THREAD -
45#include "qthread.h" -
46#include "qthread_p.h" -
47#include "qmutex.h" -
48 -
49#include <string.h> -
50 -
51QT_BEGIN_NAMESPACE -
52 -
53// #define THREADSTORAGE_DEBUG -
54#ifdef THREADSTORAGE_DEBUG -
55# define DEBUG_MSG qtsDebug -
56 -
57# include <stdio.h> -
58# include <stdarg.h> -
59void qtsDebug(const char *fmt, ...) -
60{ -
61 va_list va; -
62 va_start(va, fmt); -
63 -
64 fprintf(stderr, "QThreadStorage: "); -
65 vfprintf(stderr, fmt, va); -
66 fprintf(stderr, "\n"); -
67 -
68 va_end(va); -
69} -
70#else -
71# define DEBUG_MSG if(false)qDebug -
72#endif -
73 -
74static QBasicMutex destructorsMutex; -
75typedef QVector<void (*)(void *)> DestructorMap; -
76Q_GLOBAL_STATIC(DestructorMap, destructors)
never executed: delete x;
executed: return thisGlobalStatic.pointer.load();
Execution Count:3363
partially evaluated: !thisGlobalStatic.pointer.testAndSetOrdered(0, x)
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:12
evaluated: !thisGlobalStatic.pointer.load()
TRUEFALSE
yes
Evaluation Count:12
yes
Evaluation Count:3352
partially evaluated: !thisGlobalStatic.destroyed
TRUEFALSE
yes
Evaluation Count:12
no
Evaluation Count:0
0-3363
77 -
78QThreadStorageData::QThreadStorageData(void (*func)(void *)) -
79{ -
80 QMutexLocker locker(&destructorsMutex);
executed (the execution status of this line is deduced): QMutexLocker locker(&destructorsMutex);
-
81 DestructorMap *destr = destructors();
executed (the execution status of this line is deduced): DestructorMap *destr = destructors();
-
82 if (!destr) {
partially evaluated: !destr
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:370
0-370
83 /* -
84 the destructors vector has already been destroyed, yet a new -
85 QThreadStorage is being allocated. this can only happen during global -
86 destruction, at which point we assume that there is only one thread. -
87 in order to keep QThreadStorage working, we need somewhere to store -
88 the data, best place we have in this situation is at the tail of the -
89 current thread's tls vector. the destructor is ignored, since we have -
90 no where to store it, and no way to actually call it. -
91 */ -
92 QThreadData *data = QThreadData::current();
never executed (the execution status of this line is deduced): QThreadData *data = QThreadData::current();
-
93 id = data->tls.count();
never executed (the execution status of this line is deduced): id = data->tls.count();
-
94 DEBUG_MSG("QThreadStorageData: Allocated id %d, destructor %p cannot be stored", id, func);
never executed: QMessageLogger("thread/qthreadstorage.cpp", 94, __PRETTY_FUNCTION__).debug("QThreadStorageData: Allocated id %d, destructor %p cannot be stored", id, func);
never evaluated: false
0
95 return;
never executed: return;
0
96 } -
97 for (id = 0; id < destr->count(); id++) {
evaluated: id < destr->count()
TRUEFALSE
yes
Evaluation Count:585
yes
Evaluation Count:359
359-585
98 if (destr->at(id) == 0)
evaluated: destr->at(id) == 0
TRUEFALSE
yes
Evaluation Count:11
yes
Evaluation Count:574
11-574
99 break;
executed: break;
Execution Count:11
11
100 }
executed: }
Execution Count:574
574
101 if (id == destr->count()) {
evaluated: id == destr->count()
TRUEFALSE
yes
Evaluation Count:359
yes
Evaluation Count:11
11-359
102 destr->append(func);
executed (the execution status of this line is deduced): destr->append(func);
-
103 } else {
executed: }
Execution Count:359
359
104 (*destr)[id] = func;
executed (the execution status of this line is deduced): (*destr)[id] = func;
-
105 }
executed: }
Execution Count:11
11
106 DEBUG_MSG("QThreadStorageData: Allocated id %d, destructor %p", id, func);
never executed: QMessageLogger("thread/qthreadstorage.cpp", 106, __PRETTY_FUNCTION__).debug("QThreadStorageData: Allocated id %d, destructor %p", id, func);
partially evaluated: false
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:370
0-370
107}
executed: }
Execution Count:370
370
108 -
109QThreadStorageData::~QThreadStorageData() -
110{ -
111 DEBUG_MSG("QThreadStorageData: Released id %d", id);
never executed: QMessageLogger("thread/qthreadstorage.cpp", 111, __PRETTY_FUNCTION__).debug("QThreadStorageData: Released id %d", id);
partially evaluated: false
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:368
0-368
112 QMutexLocker locker(&destructorsMutex);
executed (the execution status of this line is deduced): QMutexLocker locker(&destructorsMutex);
-
113 if (destructors())
partially evaluated: destructors()
TRUEFALSE
yes
Evaluation Count:368
no
Evaluation Count:0
0-368
114 (*destructors())[id] = 0;
executed: (*destructors())[id] = 0;
Execution Count:368
368
115}
executed: }
Execution Count:368
368
116 -
117void **QThreadStorageData::get() const -
118{ -
119 QThreadData *data = QThreadData::current();
executed (the execution status of this line is deduced): QThreadData *data = QThreadData::current();
-
120 if (!data) {
partially evaluated: !data
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:7409468
0-7409468
121 qWarning("QThreadStorage::get: QThreadStorage can only be used with threads started with QThread");
never executed (the execution status of this line is deduced): QMessageLogger("thread/qthreadstorage.cpp", 121, __PRETTY_FUNCTION__).warning("QThreadStorage::get: QThreadStorage can only be used with threads started with QThread");
-
122 return 0;
never executed: return 0;
0
123 } -
124 QVector<void *> &tls = data->tls;
executed (the execution status of this line is deduced): QVector<void *> &tls = data->tls;
-
125 if (tls.size() <= id)
evaluated: tls.size() <= id
TRUEFALSE
yes
Evaluation Count:1574
yes
Evaluation Count:7407895
1574-7407895
126 tls.resize(id + 1);
executed: tls.resize(id + 1);
Execution Count:1573
1573
127 void **v = &tls[id];
executed (the execution status of this line is deduced): void **v = &tls[id];
-
128 -
129 DEBUG_MSG("QThreadStorageData: Returning storage %d, data %p, for thread %p",
never executed: QMessageLogger("thread/qthreadstorage.cpp", 129, __PRETTY_FUNCTION__).debug("QThreadStorageData: Returning storage %d, data %p, for thread %p", id, *v, data->thread);
partially evaluated: false
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:7409469
0-7409469
130 id,
never executed: QMessageLogger("thread/qthreadstorage.cpp", 129, __PRETTY_FUNCTION__).debug("QThreadStorageData: Returning storage %d, data %p, for thread %p", id, *v, data->thread);
0
131 *v,
never executed: QMessageLogger("thread/qthreadstorage.cpp", 129, __PRETTY_FUNCTION__).debug("QThreadStorageData: Returning storage %d, data %p, for thread %p", id, *v, data->thread);
0
132 data->thread);
never executed: QMessageLogger("thread/qthreadstorage.cpp", 129, __PRETTY_FUNCTION__).debug("QThreadStorageData: Returning storage %d, data %p, for thread %p", id, *v, data->thread);
0
133 -
134 return *v ? v : 0;
executed: return *v ? v : 0;
Execution Count:7409469
7409469
135} -
136 -
137void **QThreadStorageData::set(void *p) -
138{ -
139 QThreadData *data = QThreadData::current();
executed (the execution status of this line is deduced): QThreadData *data = QThreadData::current();
-
140 if (!data) {
partially evaluated: !data
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:2467
0-2467
141 qWarning("QThreadStorage::set: QThreadStorage can only be used with threads started with QThread");
never executed (the execution status of this line is deduced): QMessageLogger("thread/qthreadstorage.cpp", 141, __PRETTY_FUNCTION__).warning("QThreadStorage::set: QThreadStorage can only be used with threads started with QThread");
-
142 return 0;
never executed: return 0;
0
143 } -
144 QVector<void *> &tls = data->tls;
executed (the execution status of this line is deduced): QVector<void *> &tls = data->tls;
-
145 if (tls.size() <= id)
evaluated: tls.size() <= id
TRUEFALSE
yes
Evaluation Count:6
yes
Evaluation Count:2462
6-2462
146 tls.resize(id + 1);
executed: tls.resize(id + 1);
Execution Count:6
6
147 -
148 void *&value = tls[id];
executed (the execution status of this line is deduced): void *&value = tls[id];
-
149 // delete any previous data -
150 if (value != 0) {
evaluated: value != 0
TRUEFALSE
yes
Evaluation Count:198
yes
Evaluation Count:2270
198-2270
151 DEBUG_MSG("QThreadStorageData: Deleting previous storage %d, data %p, for thread %p",
never executed: QMessageLogger("thread/qthreadstorage.cpp", 151, __PRETTY_FUNCTION__).debug("QThreadStorageData: Deleting previous storage %d, data %p, for thread %p", id, value, data->thread);
partially evaluated: false
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:198
0-198
152 id,
never executed: QMessageLogger("thread/qthreadstorage.cpp", 151, __PRETTY_FUNCTION__).debug("QThreadStorageData: Deleting previous storage %d, data %p, for thread %p", id, value, data->thread);
0
153 value,
never executed: QMessageLogger("thread/qthreadstorage.cpp", 151, __PRETTY_FUNCTION__).debug("QThreadStorageData: Deleting previous storage %d, data %p, for thread %p", id, value, data->thread);
0
154 data->thread);
never executed: QMessageLogger("thread/qthreadstorage.cpp", 151, __PRETTY_FUNCTION__).debug("QThreadStorageData: Deleting previous storage %d, data %p, for thread %p", id, value, data->thread);
0
155 -
156 QMutexLocker locker(&destructorsMutex);
executed (the execution status of this line is deduced): QMutexLocker locker(&destructorsMutex);
-
157 DestructorMap *destr = destructors();
executed (the execution status of this line is deduced): DestructorMap *destr = destructors();
-
158 void (*destructor)(void *) = destr ? destr->value(id) : 0;
partially evaluated: destr
TRUEFALSE
yes
Evaluation Count:198
no
Evaluation Count:0
0-198
159 locker.unlock();
executed (the execution status of this line is deduced): locker.unlock();
-
160 -
161 void *q = value;
executed (the execution status of this line is deduced): void *q = value;
-
162 value = 0;
executed (the execution status of this line is deduced): value = 0;
-
163 -
164 if (destructor)
partially evaluated: destructor
TRUEFALSE
yes
Evaluation Count:198
no
Evaluation Count:0
0-198
165 destructor(q);
executed: destructor(q);
Execution Count:198
198
166 }
executed: }
Execution Count:198
198
167 -
168 // store new data -
169 value = p;
executed (the execution status of this line is deduced): value = p;
-
170 DEBUG_MSG("QThreadStorageData: Set storage %d for thread %p to %p", id, data->thread, p);
never executed: QMessageLogger("thread/qthreadstorage.cpp", 170, __PRETTY_FUNCTION__).debug("QThreadStorageData: Set storage %d for thread %p to %p", id, data->thread, p);
partially evaluated: false
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:2468
0-2468
171 return &value;
executed: return &value;
Execution Count:2467
2467
172} -
173 -
174void QThreadStorageData::finish(void **p) -
175{ -
176 QVector<void *> *tls = reinterpret_cast<QVector<void *> *>(p);
executed (the execution status of this line is deduced): QVector<void *> *tls = reinterpret_cast<QVector<void *> *>(p);
-
177 if (!tls || tls->isEmpty() || !destructors())
partially evaluated: !tls
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:1717849
evaluated: tls->isEmpty()
TRUEFALSE
yes
Evaluation Count:1716984
yes
Evaluation Count:871
partially evaluated: !destructors()
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:871
0-1717849
178 return; // nothing to do
executed: return;
Execution Count:1716986
1716986
179 -
180 DEBUG_MSG("QThreadStorageData: Destroying storage for thread %p", QThread::currentThread());
never executed: QMessageLogger("thread/qthreadstorage.cpp", 180, __PRETTY_FUNCTION__).debug("QThreadStorageData: Destroying storage for thread %p", QThread::currentThread());
partially evaluated: false
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:871
0-871
181 while (!tls->isEmpty()) {
evaluated: !tls->isEmpty()
TRUEFALSE
yes
Evaluation Count:2506
yes
Evaluation Count:871
871-2506
182 void *&value = tls->last();
executed (the execution status of this line is deduced): void *&value = tls->last();
-
183 void *q = value;
executed (the execution status of this line is deduced): void *q = value;
-
184 value = 0;
executed (the execution status of this line is deduced): value = 0;
-
185 int i = tls->size() - 1;
executed (the execution status of this line is deduced): int i = tls->size() - 1;
-
186 tls->resize(i);
executed (the execution status of this line is deduced): tls->resize(i);
-
187 -
188 if (!q) {
evaluated: !q
TRUEFALSE
yes
Evaluation Count:1317
yes
Evaluation Count:1188
1188-1317
189 // data already deleted -
190 continue;
executed: continue;
Execution Count:1317
1317
191 } -
192 -
193 QMutexLocker locker(&destructorsMutex);
executed (the execution status of this line is deduced): QMutexLocker locker(&destructorsMutex);
-
194 void (*destructor)(void *) = destructors()->value(i);
executed (the execution status of this line is deduced): void (*destructor)(void *) = destructors()->value(i);
-
195 locker.unlock();
executed (the execution status of this line is deduced): locker.unlock();
-
196 -
197 if (!destructor) {
partially evaluated: !destructor
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:1189
0-1189
198 if (QThread::currentThread())
never evaluated: QThread::currentThread()
0
199 qWarning("QThreadStorage: Thread %p exited after QThreadStorage %d destroyed",
never executed: QMessageLogger("thread/qthreadstorage.cpp", 199, __PRETTY_FUNCTION__).warning("QThreadStorage: Thread %p exited after QThreadStorage %d destroyed", QThread::currentThread(), i);
0
200 QThread::currentThread(), i);
never executed: QMessageLogger("thread/qthreadstorage.cpp", 199, __PRETTY_FUNCTION__).warning("QThreadStorage: Thread %p exited after QThreadStorage %d destroyed", QThread::currentThread(), i);
0
201 continue;
never executed: continue;
0
202 } -
203 destructor(q); //crash here might mean the thread exited after qthreadstorage was destroyed
executed (the execution status of this line is deduced): destructor(q);
-
204 -
205 if (tls->size() > i) {
evaluated: tls->size() > i
TRUEFALSE
yes
Evaluation Count:16
yes
Evaluation Count:1173
16-1173
206 //re reset the tls in case it has been recreated by its own destructor. -
207 (*tls)[i] = 0;
executed (the execution status of this line is deduced): (*tls)[i] = 0;
-
208 }
executed: }
Execution Count:16
16
209 }
executed: }
Execution Count:1189
1189
210 tls->clear();
executed (the execution status of this line is deduced): tls->clear();
-
211}
executed: }
Execution Count:871
871
212 -
213/*! -
214 \class QThreadStorage -
215 \inmodule QtCore -
216 \brief The QThreadStorage class provides per-thread data storage. -
217 -
218 \threadsafe -
219 -
220 \ingroup thread -
221 -
222 QThreadStorage is a template class that provides per-thread data -
223 storage. -
224 -
225 The setLocalData() function stores a single thread-specific value -
226 for the calling thread. The data can be accessed later using -
227 localData(). -
228 -
229 The hasLocalData() function allows the programmer to determine if -
230 data has previously been set using the setLocalData() function. -
231 This is also useful for lazy initializiation. -
232 -
233 If T is a pointer type, QThreadStorage takes ownership of the data -
234 (which must be created on the heap with \c new) and deletes it when -
235 the thread exits, either normally or via termination. -
236 -
237 For example, the following code uses QThreadStorage to store a -
238 single cache for each thread that calls the cacheObject() and -
239 removeFromCache() functions. The cache is automatically -
240 deleted when the calling thread exits. -
241 -
242 \snippet threads/threads.cpp 7 -
243 \snippet threads/threads.cpp 8 -
244 \snippet threads/threads.cpp 9 -
245 -
246 \section1 Caveats -
247 -
248 \list -
249 -
250 \li The QThreadStorage destructor does not delete per-thread data. -
251 QThreadStorage only deletes per-thread data when the thread exits -
252 or when setLocalData() is called multiple times. -
253 -
254 \li QThreadStorage can be used to store data for the \c main() -
255 thread. QThreadStorage deletes all data set for the \c main() -
256 thread when QApplication is destroyed, regardless of whether or -
257 not the \c main() thread has actually finished. -
258 -
259 \endlist -
260 -
261 \sa QThread -
262*/ -
263 -
264/*! -
265 \fn QThreadStorage::QThreadStorage() -
266 -
267 Constructs a new per-thread data storage object. -
268*/ -
269 -
270/*! -
271 \fn QThreadStorage::~QThreadStorage() -
272 -
273 Destroys the per-thread data storage object. -
274 -
275 Note: The per-thread data stored is not deleted. Any data left -
276 in QThreadStorage is leaked. Make sure that all threads using -
277 QThreadStorage have exited before deleting the QThreadStorage. -
278 -
279 \sa hasLocalData() -
280*/ -
281 -
282/*! -
283 \fn bool QThreadStorage::hasLocalData() const -
284 -
285 If T is a pointer type, returns true if the calling thread has -
286 non-zero data available. -
287 -
288 If T is a value type, returns whether the data has already been -
289 constructed by calling setLocalData or localData. -
290 -
291 \sa localData() -
292*/ -
293 -
294/*! -
295 \fn T &QThreadStorage::localData() -
296 -
297 Returns a reference to the data that was set by the calling -
298 thread. -
299 -
300 If no data has been set, this will create a default constructed -
301 instance of type T. -
302 -
303 \sa hasLocalData() -
304*/ -
305 -
306/*! -
307 \fn const T QThreadStorage::localData() const -
308 \overload -
309 -
310 Returns a copy of the data that was set by the calling thread. -
311 -
312 \sa hasLocalData() -
313*/ -
314 -
315/*! -
316 \fn void QThreadStorage::setLocalData(T data) -
317 -
318 Sets the local data for the calling thread to \a data. It can be -
319 accessed later using the localData() functions. -
320 -
321 If T is a pointer type, QThreadStorage takes ownership of the data -
322 and deletes it automatically either when the thread exits (either -
323 normally or via termination) or when setLocalData() is called again. -
324 -
325 \sa localData(), hasLocalData() -
326*/ -
327 -
328#endif // QT_NO_THREAD -
329 -
330QT_END_NAMESPACE -
331 -
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial