1
/****************************************************************************
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
5
** This file is part of the core module of the Qt Toolkit.
7
** This file may be distributed under the terms of the Q Public License
8
** as defined by Trolltech AS of Norway and appearing in the file
9
** LICENSE.QPL included in the packaging of this file.
11
** This file may be distributed and/or modified under the terms of the
12
** GNU General Public License version 2 as published by the Free Software
13
** Foundation and appearing in the file LICENSE.GPL included in the
14
** packaging of this file.
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
17
** information about Qt Commercial License Agreements.
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
21
** Contact info@trolltech.com if any conditions of this licensing are
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27
****************************************************************************/
29
#include "qthreadstorage.h"
32
#include "qthread_p.h"
37
// #define THREADSTORAGE_DEBUG
38
#ifdef THREADSTORAGE_DEBUG
41
# define DEBUG if(false)qDebug
45
// 256 maximum + 1 used in QRegExp
46
static const int MAX_THREAD_STORAGE = 257;
48
Q_GLOBAL_STATIC(QMutex, mutex)
50
static bool thread_storage_init = false;
54
} thread_storage_usage[MAX_THREAD_STORAGE];
57
QThreadStorageData::QThreadStorageData(void (*func)(void *))
60
QMutexLocker locker(mutex());
62
// make sure things are initialized
63
if (! thread_storage_init)
64
memset(thread_storage_usage, 0, sizeof(thread_storage_usage));
65
thread_storage_init = true;
67
for (; id < MAX_THREAD_STORAGE; ++id) {
68
if (!thread_storage_usage[id].used)
72
Q_ASSERT(id >= 0 && id < MAX_THREAD_STORAGE);
73
thread_storage_usage[id].used = true;
74
thread_storage_usage[id].func = func;
76
DEBUG("QThreadStorageData: allocated id %d", id);
79
QThreadStorageData::~QThreadStorageData()
81
QMutexLocker locker(mutex());
83
// thread_storage_usage[id].used = false;
84
thread_storage_usage[id].func = 0;
86
DEBUG("QThreadStorageData: released id %d", id);
89
void **QThreadStorageData::get() const
91
QThread *thread = QThread::currentThread();
93
qWarning("QThreadStorage can only be used with threads started with QThread");
96
QThreadData *data = QThreadData::get(thread);
97
return data->tls && data->tls[id] ? &data->tls[id] : 0;
100
void **QThreadStorageData::set(void *p)
102
QThread *thread = QThread::currentThread();
104
qWarning("QThreadStorage can only be used with threads started with QThread");
107
QThreadData *data = QThreadData::get(thread);
109
DEBUG("QThreadStorageData: allocating storage %d for thread %p",
110
id, QThread::currentThread());
112
data->tls = new void*[MAX_THREAD_STORAGE];
113
memset(data->tls, 0, sizeof(void*) * MAX_THREAD_STORAGE);
116
// delete any previous data
118
DEBUG("QThreadStorageData: deleting previous storage %d for thread %p",
119
id, QThread::currentThread());
121
void *q = data->tls[id];
123
thread_storage_usage[id].func(q);
128
DEBUG("QThreadStorageData: set storage %d for thread %p to %p",
129
id, QThread::currentThread(), p);
130
return &data->tls[id];
133
void QThreadStorageData::finish(void **tls)
135
if (!tls) return; // nothing to do
137
DEBUG("QThreadStorageData: destroying storage for thread %p",
138
QThread::currentThread());
140
for (int i = 0; i < MAX_THREAD_STORAGE; ++i) {
141
if (!tls[i]) continue;
142
if (!thread_storage_usage[i].func) {
143
qWarning("QThreadStorage: thread %p exited after QThreadStorage destroyed",
144
QThread::currentThread());
150
thread_storage_usage[i].func(q);
157
\class QThreadStorage
158
\brief The QThreadStorage class provides per-thread data storage.
166
QThreadStorage is a template class that provides per-thread data
169
\e{Note that due to compiler limitations, QThreadStorage can only
172
The setLocalData() function stores a single thread-specific value
173
for the calling thread. The data can be accessed later using
174
localData(). QThreadStorage takes ownership of the data (which
175
must be created on the heap with \c new) and deletes it when the
176
thread exits, either normally or via termination.
178
The hasLocalData() function allows the programmer to determine if
179
data has previously been set using the setLocalData() function.
180
This is also useful for lazy initializiation.
182
For example, the following code uses QThreadStorage to store a
183
single cache for each thread that calls the cacheObject() and
184
removeFromCache() functions. The cache is automatically
185
deleted when the calling thread exits.
187
\quotefromfile snippets/threads/threads.cpp
188
\skipto QThreadStorage<
189
\printuntil cacheObject
190
\printuntil removeFromCache
197
\o As noted above, QThreadStorage can only store pointers due to
198
compiler limitations.
200
\o The QThreadStorage destructor does not delete per-thread data.
201
QThreadStorage only deletes per-thread data when the thread exits
202
or when setLocalData() is called multiple times.
204
\o QThreadStorage can only be used with threads started with
205
QThread. It cannot be used with threads started using
206
platform-specific APIs.
208
\o As a corollary to the above, platform-specific APIs cannot be
209
used to exit or terminate a QThread using QThreadStorage. Doing so
210
will cause all per-thread data to be leaked. See QThread::exit()
211
and QThread::terminate().
213
\o QThreadStorage can be used to store data for the \c main()
214
thread after QApplication has been constructed. QThreadStorage
215
deletes all data set for the \c main() thread when QApplication is
216
destroyed, regardless of whether or not the \c main() thread has
219
\o The implementation of QThreadStorage limits the total number of
220
QThreadStorage objects to 256. An unlimited number of threads
221
can store per-thread data in each QThreadStorage object.
229
\fn QThreadStorage::QThreadStorage()
231
Constructs a new per-thread data storage object.
235
\fn QThreadStorage::~QThreadStorage()
237
Destroys the per-thread data storage object.
239
Note: The per-thread data stored is not deleted. Any data left
240
in QThreadStorage is leaked. Make sure that all threads using
241
QThreadStorage have exited before deleting the QThreadStorage.
247
\fn bool QThreadStorage::hasLocalData() const
249
Returns true if the calling thread has non-zero data available;
250
otherwise returns false.
256
\fn T &QThreadStorage::localData()
258
Returns a reference to the data that was set by the calling
261
Note: QThreadStorage can only store pointers. This function
262
returns a reference to the pointer that was set by the calling
263
thread. The value of this reference is 0 if no data was set by
270
\fn const T QThreadStorage::localData() const
273
Returns a copy of the data that was set by the calling thread.
275
Note: QThreadStorage can only store pointers. This function
276
returns a pointer to the data that was set by the calling thread.
277
If no data was set by the calling thread, this function returns 0.
283
\fn void QThreadStorage::setLocalData(T data)
285
Sets the local data for the calling thread to \a data. It can be
286
accessed later using the localData() functions.
288
If \a data is 0, this function deletes the previous data (if
289
any) and returns immediately.
291
If \a data is non-zero, QThreadStorage takes ownership of the \a
292
data and deletes it automatically either when the thread exits
293
(either normally or via termination) or when setLocalData() is
296
Note: QThreadStorage can only store pointers. The \a data
297
argument must be either a pointer to an object created on the heap
298
(i.e. using \c new) or 0. You should not delete \a data
299
yourself; QThreadStorage takes ownership and will delete the \a
302
\sa localData(), hasLocalData()