qthreadstorage.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/corelib/thread/qthreadstorage.cpp
Source codeSwitch to Preprocessed file
LineSourceCount
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 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 "qthreadstorage.h"-
41-
42#ifndef QT_NO_THREAD-
43#include "qthread.h"-
44#include "qthread_p.h"-
45#include "qmutex.h"-
46-
47#include <string.h>-
48-
49QT_BEGIN_NAMESPACE-
50-
51// #define THREADSTORAGE_DEBUG-
52#ifdef THREADSTORAGE_DEBUG-
53# define DEBUG_MSG qtsDebug-
54-
55# include <stdio.h>-
56# include <stdarg.h>-
57void qtsDebug(const char *fmt, ...)-
58{-
59 va_list va;-
60 va_start(va, fmt);-
61-
62 fprintf(stderr, "QThreadStorage: ");-
63 vfprintf(stderr, fmt, va);-
64 fprintf(stderr, "\n");-
65-
66 va_end(va);-
67}-
68#else-
69# define DEBUG_MSG if(false)qDebug-
70#endif-
71-
72static QBasicMutex destructorsMutex;-
73typedef QVector<void (*)(void *)> DestructorMap;-
74Q_GLOBAL_STATIC(DestructorMap, destructors)-
75-
76QThreadStorageData::QThreadStorageData(void (*func)(void *))-
77{-
78 QMutexLocker locker(&destructorsMutex);-
79 DestructorMap *destr = destructors();-
80 if (!destr) {-
81 /*-
82 the destructors vector has already been destroyed, yet a new-
83 QThreadStorage is being allocated. this can only happen during global-
84 destruction, at which point we assume that there is only one thread.-
85 in order to keep QThreadStorage working, we need somewhere to store-
86 the data, best place we have in this situation is at the tail of the-
87 current thread's tls vector. the destructor is ignored, since we have-
88 no where to store it, and no way to actually call it.-
89 */-
90 QThreadData *data = QThreadData::current();-
91 id = data->tls.count();-
92 DEBUG_MSG("QThreadStorageData: Allocated id %d, destructor %p cannot be stored", id, func);
dead code: QMessageLogger(__FILE__, 92, __PRETTY_FUNCTION__).debug("QThreadStorageData: Allocated id %d, destructor %p cannot be stored", id, func);
-
93 return;-
94 }-
95 for (id = 0; id < destr->count(); id++) {-
96 if (destr->at(id) == 0)-
97 break;-
98 }-
99 if (id == destr->count()) {-
100 destr->append(func);-
101 } else {-
102 (*destr)[id] = func;-
103 }-
104 DEBUG_MSG("QThreadStorageData: Allocated id %d, destructor %p", id, func);
dead code: QMessageLogger(__FILE__, 104, __PRETTY_FUNCTION__).debug("QThreadStorageData: Allocated id %d, destructor %p", id, func);
-
105}-
106-
107QThreadStorageData::~QThreadStorageData()-
108{-
109 DEBUG_MSG("QThreadStorageData: Released id %d", id);
dead code: QMessageLogger(__FILE__, 109, __PRETTY_FUNCTION__).debug("QThreadStorageData: Released id %d", id);
-
110 QMutexLocker locker(&destructorsMutex);-
111 if (destructors())-
112 (*destructors())[id] = 0;-
113}-
114-
115void **QThreadStorageData::get() const-
116{-
117 QThreadData *data = QThreadData::current();-
118 if (!data) {-
119 qWarning("QThreadStorage::get: QThreadStorage can only be used with threads started with QThread");-
120 return 0;-
121 }-
122 QVector<void *> &tls = data->tls;-
123 if (tls.size() <= id)-
124 tls.resize(id + 1);-
125 void **v = &tls[id];-
126-
127 DEBUG_MSG("QThreadStorageData: Returning storage %d, data %p, for thread %p",
dead code: QMessageLogger(__FILE__, 127, __PRETTY_FUNCTION__).debug("QThreadStorageData: Returning storage %d, data %p, for thread %p", id, *v, data->thread.load());
-
128 id,
dead code: QMessageLogger(__FILE__, 127, __PRETTY_FUNCTION__).debug("QThreadStorageData: Returning storage %d, data %p, for thread %p", id, *v, data->thread.load());
-
129 *v,
dead code: QMessageLogger(__FILE__, 127, __PRETTY_FUNCTION__).debug("QThreadStorageData: Returning storage %d, data %p, for thread %p", id, *v, data->thread.load());
-
130 data->thread.load());
dead code: QMessageLogger(__FILE__, 127, __PRETTY_FUNCTION__).debug("QThreadStorageData: Returning storage %d, data %p, for thread %p", id, *v, data->thread.load());
-
131-
132 return *v ? v : 0;-
133}-
134-
135void **QThreadStorageData::set(void *p)-
136{-
137 QThreadData *data = QThreadData::current();-
138 if (!data) {-
139 qWarning("QThreadStorage::set: QThreadStorage can only be used with threads started with QThread");-
140 return 0;-
141 }-
142 QVector<void *> &tls = data->tls;-
143 if (tls.size() <= id)-
144 tls.resize(id + 1);-
145-
146 void *&value = tls[id];-
147 // delete any previous data-
148 if (value != 0) {-
149 DEBUG_MSG("QThreadStorageData: Deleting previous storage %d, data %p, for thread %p",
dead code: QMessageLogger(__FILE__, 149, __PRETTY_FUNCTION__).debug("QThreadStorageData: Deleting previous storage %d, data %p, for thread %p", id, value, data->thread.load());
-
150 id,
dead code: QMessageLogger(__FILE__, 149, __PRETTY_FUNCTION__).debug("QThreadStorageData: Deleting previous storage %d, data %p, for thread %p", id, value, data->thread.load());
-
151 value,
dead code: QMessageLogger(__FILE__, 149, __PRETTY_FUNCTION__).debug("QThreadStorageData: Deleting previous storage %d, data %p, for thread %p", id, value, data->thread.load());
-
152 data->thread.load());
dead code: QMessageLogger(__FILE__, 149, __PRETTY_FUNCTION__).debug("QThreadStorageData: Deleting previous storage %d, data %p, for thread %p", id, value, data->thread.load());
-
153-
154 QMutexLocker locker(&destructorsMutex);-
155 DestructorMap *destr = destructors();-
156 void (*destructor)(void *) = destr ? destr->value(id) : 0;-
157 locker.unlock();-
158-
159 void *q = value;-
160 value = 0;-
161-
162 if (destructor)-
163 destructor(q);-
164 }-
165-
166 // store new data-
167 value = p;-
168 DEBUG_MSG("QThreadStorageData: Set storage %d for thread %p to %p", id, data->thread.load(), p);
dead code: QMessageLogger(__FILE__, 168, __PRETTY_FUNCTION__).debug("QThreadStorageData: Set storage %d for thread %p to %p", id, data->thread.load(), p);
-
169 return &value;-
170}-
171-
172void QThreadStorageData::finish(void **p)-
173{-
174 QVector<void *> *tls = reinterpret_cast<QVector<void *> *>(p);-
175 if (!tls || tls->isEmpty() || !destructors())-
176 return; // nothing to do-
177-
178 DEBUG_MSG("QThreadStorageData: Destroying storage for thread %p", QThread::currentThread());
dead code: QMessageLogger(__FILE__, 178, __PRETTY_FUNCTION__).debug("QThreadStorageData: Destroying storage for thread %p", QThread::currentThread());
-
179 while (!tls->isEmpty()) {-
180 void *&value = tls->last();-
181 void *q = value;-
182 value = 0;-
183 int i = tls->size() - 1;-
184 tls->resize(i);-
185-
186 if (!q) {-
187 // data already deleted-
188 continue;-
189 }-
190-
191 QMutexLocker locker(&destructorsMutex);-
192 void (*destructor)(void *) = destructors()->value(i);-
193 locker.unlock();-
194-
195 if (!destructor) {-
196 if (QThread::currentThread())-
197 qWarning("QThreadStorage: Thread %p exited after QThreadStorage %d destroyed",-
198 QThread::currentThread(), i);-
199 continue;-
200 }-
201 destructor(q); //crash here might mean the thread exited after qthreadstorage was destroyed-
202-
203 if (tls->size() > i) {-
204 //re reset the tls in case it has been recreated by its own destructor.-
205 (*tls)[i] = 0;-
206 }-
207 }-
208 tls->clear();-
209}-
210-
211/*!-
212 \class QThreadStorage-
213 \inmodule QtCore-
214 \brief The QThreadStorage class provides per-thread data storage.-
215-
216 \threadsafe-
217-
218 \ingroup thread-
219-
220 QThreadStorage is a template class that provides per-thread data-
221 storage.-
222-
223 The setLocalData() function stores a single thread-specific value-
224 for the calling thread. The data can be accessed later using-
225 localData().-
226-
227 The hasLocalData() function allows the programmer to determine if-
228 data has previously been set using the setLocalData() function.-
229 This is also useful for lazy initializiation.-
230-
231 If T is a pointer type, QThreadStorage takes ownership of the data-
232 (which must be created on the heap with \c new) and deletes it when-
233 the thread exits, either normally or via termination.-
234-
235 For example, the following code uses QThreadStorage to store a-
236 single cache for each thread that calls the cacheObject() and-
237 removeFromCache() functions. The cache is automatically-
238 deleted when the calling thread exits.-
239-
240 \snippet threads/threads.cpp 7-
241 \snippet threads/threads.cpp 8-
242 \snippet threads/threads.cpp 9-
243-
244 \section1 Caveats-
245-
246 \list-
247-
248 \li The QThreadStorage destructor does not delete per-thread data.-
249 QThreadStorage only deletes per-thread data when the thread exits-
250 or when setLocalData() is called multiple times.-
251-
252 \li QThreadStorage can be used to store data for the \c main()-
253 thread. QThreadStorage deletes all data set for the \c main()-
254 thread when QApplication is destroyed, regardless of whether or-
255 not the \c main() thread has actually finished.-
256-
257 \endlist-
258-
259 \sa QThread-
260*/-
261-
262/*!-
263 \fn QThreadStorage::QThreadStorage()-
264-
265 Constructs a new per-thread data storage object.-
266*/-
267-
268/*!-
269 \fn QThreadStorage::~QThreadStorage()-
270-
271 Destroys the per-thread data storage object.-
272-
273 Note: The per-thread data stored is not deleted. Any data left-
274 in QThreadStorage is leaked. Make sure that all threads using-
275 QThreadStorage have exited before deleting the QThreadStorage.-
276-
277 \sa hasLocalData()-
278*/-
279-
280/*!-
281 \fn bool QThreadStorage::hasLocalData() const-
282-
283 If T is a pointer type, returns \c true if the calling thread has-
284 non-zero data available.-
285-
286 If T is a value type, returns whether the data has already been-
287 constructed by calling setLocalData or localData.-
288-
289 \sa localData()-
290*/-
291-
292/*!-
293 \fn T &QThreadStorage::localData()-
294-
295 Returns a reference to the data that was set by the calling-
296 thread.-
297-
298 If no data has been set, this will create a default constructed-
299 instance of type T.-
300-
301 \sa hasLocalData()-
302*/-
303-
304/*!-
305 \fn const T QThreadStorage::localData() const-
306 \overload-
307-
308 Returns a copy of the data that was set by the calling thread.-
309-
310 \sa hasLocalData()-
311*/-
312-
313/*!-
314 \fn void QThreadStorage::setLocalData(T data)-
315-
316 Sets the local data for the calling thread to \a data. It can be-
317 accessed later using the localData() functions.-
318-
319 If T is a pointer type, QThreadStorage takes ownership of the data-
320 and deletes it automatically either when the thread exits (either-
321 normally or via termination) or when setLocalData() is called again.-
322-
323 \sa localData(), hasLocalData()-
324*/-
325-
326#endif // QT_NO_THREAD-
327-
328QT_END_NAMESPACE-
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9