Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qthreadstorage.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qthreadstorage.h"
5
6#include "qthread.h"
7#include "qthread_p.h"
8#include "qmutex.h"
9
10#include <string.h>
11
13
14// #define THREADSTORAGE_DEBUG
15#ifdef THREADSTORAGE_DEBUG
16# define DEBUG_MSG qtsDebug
17
18# include <stdio.h>
19# include <stdarg.h>
20void qtsDebug(const char *fmt, ...)
21{
22 va_list va;
23 va_start(va, fmt);
24
25 fprintf(stderr, "QThreadStorage: ");
26 vfprintf(stderr, fmt, va);
27 fprintf(stderr, "\n");
28
29 va_end(va);
30}
31#else
32# define DEBUG_MSG if (false)qDebug
33#endif
34
35Q_CONSTINIT static QBasicMutex destructorsMutex;
36typedef QList<void (*)(void *)> DestructorMap;
38
39QThreadStorageData::QThreadStorageData(void (*func)(void *))
40{
42 DestructorMap *destr = destructors();
43 if (!destr) {
44 /*
45 the destructors vector has already been destroyed, yet a new
46 QThreadStorage is being allocated. this can only happen during global
47 destruction, at which point we assume that there is only one thread.
48 in order to keep QThreadStorage working, we need somewhere to store
49 the data, best place we have in this situation is at the tail of the
50 current thread's tls vector. the destructor is ignored, since we have
51 no where to store it, and no way to actually call it.
52 */
54 id = data->tls.size();
55 DEBUG_MSG("QThreadStorageData: Allocated id %d, destructor %p cannot be stored", id, func);
56 return;
57 }
58 for (id = 0; id < destr->size(); id++) {
59 if (destr->at(id) == nullptr)
60 break;
61 }
62 if (id == destr->size()) {
63 destr->append(func);
64 } else {
65 (*destr)[id] = func;
66 }
67 DEBUG_MSG("QThreadStorageData: Allocated id %d, destructor %p", id, func);
68}
69
70QThreadStorageData::~QThreadStorageData()
71{
72 DEBUG_MSG("QThreadStorageData: Released id %d", id);
74 if (destructors())
75 (*destructors())[id] = nullptr;
76}
77
78void **QThreadStorageData::get() const
79{
81 if (!data) {
82 qWarning("QThreadStorage::get: QThreadStorage can only be used with threads started with QThread");
83 return nullptr;
84 }
85 QList<void *> &tls = data->tls;
86 if (tls.size() <= id)
87 tls.resize(id + 1);
88 void **v = &tls[id];
89
90 DEBUG_MSG("QThreadStorageData: Returning storage %d, data %p, for thread %p",
91 id,
92 *v,
93 data->thread.loadRelaxed());
94
95 return *v ? v : nullptr;
96}
97
98void **QThreadStorageData::set(void *p)
99{
101 if (!data) {
102 qWarning("QThreadStorage::set: QThreadStorage can only be used with threads started with QThread");
103 return nullptr;
104 }
105 QList<void *> &tls = data->tls;
106 if (tls.size() <= id)
107 tls.resize(id + 1);
108
109 void *&value = tls[id];
110 // delete any previous data
111 if (value != nullptr) {
112 DEBUG_MSG("QThreadStorageData: Deleting previous storage %d, data %p, for thread %p",
113 id,
114 value,
115 data->thread.loadRelaxed());
116
118 DestructorMap *destr = destructors();
119 void (*destructor)(void *) = destr ? destr->value(id) : nullptr;
120 locker.unlock();
121
122 void *q = value;
123 value = nullptr;
124
125 if (destructor)
126 destructor(q);
127 }
128
129 // store new data
130 value = p;
131 DEBUG_MSG("QThreadStorageData: Set storage %d for thread %p to %p", id, data->thread.loadRelaxed(), p);
132 return &value;
133}
134
135void QThreadStorageData::finish(void **p)
136{
137 QList<void *> *tls = reinterpret_cast<QList<void *> *>(p);
138 if (!tls || tls->isEmpty() || !destructors())
139 return; // nothing to do
140
141 DEBUG_MSG("QThreadStorageData: Destroying storage for thread %p", QThread::currentThread());
142 while (!tls->isEmpty()) {
143 void *&value = tls->last();
144 void *q = value;
145 value = nullptr;
146 int i = tls->size() - 1;
147 tls->resize(i);
148
149 if (!q) {
150 // data already deleted
151 continue;
152 }
153
155 void (*destructor)(void *) = destructors()->value(i);
156 locker.unlock();
157
158 if (!destructor) {
160 qWarning("QThreadStorage: Thread %p exited after QThreadStorage %d destroyed",
162 continue;
163 }
164 destructor(q); //crash here might mean the thread exited after qthreadstorage was destroyed
165
166 if (tls->size() > i) {
167 //re reset the tls in case it has been recreated by its own destructor.
168 (*tls)[i] = nullptr;
169 }
170 }
171 tls->clear();
172}
173
Definition qlist.h:75
\inmodule QtCore
Definition qmutex.h:313
\inmodule QtCore
Definition qmutex.h:281
static Q_AUTOTEST_EXPORT QThreadData * current(bool createIfNecessary=true)
Definition qthread.cpp:1087
static QThread * currentThread()
Definition qthread.cpp:1039
Combined button and popup list for selecting options.
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qWarning
Definition qlogging.h:166
GLsizei const GLfloat * v
[13]
GLenum GLuint id
[7]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum func
Definition qopenglext.h:663
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLfloat GLfloat p
[1]
QList< void(*)(void *) DestructorMap)
#define DEBUG_MSG
static Q_CONSTINIT QBasicMutex destructorsMutex
QVideoFrameFormat::PixelFormat fmt