~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/corelib/thread/qthreadstorage.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the core module of the Qt Toolkit.
 
6
**
 
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.
 
10
**
 
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.
 
15
**
 
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.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
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.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
#include "qthreadstorage.h"
 
30
 
 
31
#include "qthread.h"
 
32
#include "qthread_p.h"
 
33
#include "qmutex.h"
 
34
 
 
35
#include <string.h>
 
36
 
 
37
// #define THREADSTORAGE_DEBUG
 
38
#ifdef THREADSTORAGE_DEBUG
 
39
#  define DEBUG qDebug
 
40
#else
 
41
#  define DEBUG if(false)qDebug
 
42
#endif
 
43
 
 
44
 
 
45
// 256 maximum + 1 used in QRegExp
 
46
static const int MAX_THREAD_STORAGE = 257;
 
47
 
 
48
Q_GLOBAL_STATIC(QMutex, mutex)
 
49
 
 
50
static bool thread_storage_init = false;
 
51
static struct {
 
52
    bool used;
 
53
    void (*func)(void *);
 
54
} thread_storage_usage[MAX_THREAD_STORAGE];
 
55
 
 
56
 
 
57
QThreadStorageData::QThreadStorageData(void (*func)(void *))
 
58
    : id(0)
 
59
{
 
60
    QMutexLocker locker(mutex());
 
61
 
 
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;
 
66
 
 
67
    for (; id < MAX_THREAD_STORAGE; ++id) {
 
68
        if (!thread_storage_usage[id].used)
 
69
            break;
 
70
    }
 
71
 
 
72
    Q_ASSERT(id >= 0 && id < MAX_THREAD_STORAGE);
 
73
    thread_storage_usage[id].used = true;
 
74
    thread_storage_usage[id].func = func;
 
75
 
 
76
    DEBUG("QThreadStorageData: allocated id %d", id);
 
77
}
 
78
 
 
79
QThreadStorageData::~QThreadStorageData()
 
80
{
 
81
    QMutexLocker locker(mutex());
 
82
 
 
83
    // thread_storage_usage[id].used = false;
 
84
    thread_storage_usage[id].func = 0;
 
85
 
 
86
    DEBUG("QThreadStorageData: released id %d", id);
 
87
}
 
88
 
 
89
void **QThreadStorageData::get() const
 
90
{
 
91
    QThread *thread = QThread::currentThread();
 
92
    if (!thread) {
 
93
        qWarning("QThreadStorage can only be used with threads started with QThread");
 
94
        return 0;
 
95
    }
 
96
    QThreadData *data = QThreadData::get(thread);
 
97
    return data->tls && data->tls[id] ? &data->tls[id] : 0;
 
98
}
 
99
 
 
100
void **QThreadStorageData::set(void *p)
 
101
{
 
102
    QThread *thread = QThread::currentThread();
 
103
    if (!thread) {
 
104
        qWarning("QThreadStorage can only be used with threads started with QThread");
 
105
        return 0;
 
106
    }
 
107
    QThreadData *data = QThreadData::get(thread);
 
108
    if (!data->tls) {
 
109
        DEBUG("QThreadStorageData: allocating storage %d for thread %p",
 
110
              id, QThread::currentThread());
 
111
 
 
112
        data->tls = new void*[MAX_THREAD_STORAGE];
 
113
        memset(data->tls, 0, sizeof(void*) * MAX_THREAD_STORAGE);
 
114
    }
 
115
 
 
116
    // delete any previous data
 
117
    if (data->tls[id]) {
 
118
        DEBUG("QThreadStorageData: deleting previous storage %d for thread %p",
 
119
              id, QThread::currentThread());
 
120
 
 
121
        void *q = data->tls[id];
 
122
        data->tls[id] = 0;
 
123
        thread_storage_usage[id].func(q);
 
124
    }
 
125
 
 
126
    // store new data
 
127
    data->tls[id] = p;
 
128
    DEBUG("QThreadStorageData: set storage %d for thread %p to %p",
 
129
          id, QThread::currentThread(), p);
 
130
    return &data->tls[id];
 
131
}
 
132
 
 
133
void QThreadStorageData::finish(void **tls)
 
134
{
 
135
    if (!tls) return; // nothing to do
 
136
 
 
137
    DEBUG("QThreadStorageData: destroying storage for thread %p",
 
138
          QThread::currentThread());
 
139
 
 
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());
 
145
            continue;
 
146
        }
 
147
 
 
148
        void *q = tls[i];
 
149
        tls[i] = 0;
 
150
        thread_storage_usage[i].func(q);
 
151
    }
 
152
 
 
153
    delete [] tls;
 
154
}
 
155
 
 
156
/*!
 
157
    \class QThreadStorage
 
158
    \brief The QThreadStorage class provides per-thread data storage.
 
159
 
 
160
    \threadsafe
 
161
 
 
162
    \ingroup thread
 
163
    \ingroup environment
 
164
    \mainclass
 
165
 
 
166
    QThreadStorage is a template class that provides per-thread data
 
167
    storage.
 
168
 
 
169
    \e{Note that due to compiler limitations, QThreadStorage can only
 
170
    store pointers.}
 
171
 
 
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.
 
177
 
 
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.
 
181
 
 
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.
 
186
 
 
187
    \quotefromfile snippets/threads/threads.cpp
 
188
    \skipto QThreadStorage<
 
189
    \printuntil cacheObject
 
190
    \printuntil removeFromCache
 
191
    \printuntil /^\}$/
 
192
 
 
193
    \section1 Caveats
 
194
 
 
195
    \list
 
196
 
 
197
    \o As noted above, QThreadStorage can only store pointers due to
 
198
    compiler limitations.
 
199
 
 
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.
 
203
 
 
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.
 
207
 
 
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().
 
212
 
 
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
 
217
    actually finished.
 
218
 
 
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.
 
222
 
 
223
    \endlist
 
224
 
 
225
    \sa QThread
 
226
*/
 
227
 
 
228
/*!
 
229
    \fn QThreadStorage::QThreadStorage()
 
230
 
 
231
    Constructs a new per-thread data storage object.
 
232
*/
 
233
 
 
234
/*!
 
235
    \fn QThreadStorage::~QThreadStorage()
 
236
 
 
237
    Destroys the per-thread data storage object.
 
238
 
 
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.
 
242
 
 
243
    \sa hasLocalData()
 
244
*/
 
245
 
 
246
/*!
 
247
    \fn bool QThreadStorage::hasLocalData() const
 
248
 
 
249
    Returns true if the calling thread has non-zero data available;
 
250
    otherwise returns false.
 
251
 
 
252
    \sa localData()
 
253
*/
 
254
 
 
255
/*!
 
256
    \fn T &QThreadStorage::localData()
 
257
 
 
258
    Returns a reference to the data that was set by the calling
 
259
    thread.
 
260
 
 
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
 
264
    the calling thread,
 
265
 
 
266
    \sa hasLocalData()
 
267
*/
 
268
 
 
269
/*!
 
270
    \fn const T QThreadStorage::localData() const
 
271
    \overload
 
272
 
 
273
    Returns a copy of the data that was set by the calling thread.
 
274
 
 
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.
 
278
 
 
279
    \sa hasLocalData()
 
280
*/
 
281
 
 
282
/*!
 
283
    \fn void QThreadStorage::setLocalData(T data)
 
284
 
 
285
    Sets the local data for the calling thread to \a data. It can be
 
286
    accessed later using the localData() functions.
 
287
 
 
288
    If \a data is 0, this function deletes the previous data (if
 
289
    any) and returns immediately.
 
290
 
 
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
 
294
    called again.
 
295
 
 
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
 
300
    data itself.
 
301
 
 
302
    \sa localData(), hasLocalData()
 
303
*/