QObject: use per-thread storage for qFlagLocation()
qFlagLocation() uses a global char* array to transport source location information from the connect() side to the metaobject side. The size of the array is 2 (two), which just about suffices for a single connect() statement. Obviously, if more than one thread makes a (_any_) connection at the same time, the data is useless and, worse, there's a data race. The non-reentrancy of qFlagLocations() cannot and need not be fixed, but use a per-thread flagged_locations array in QThreadData so threads don't disturb each other. Task-number: QTBUG-3680 Change-Id: If1797c60751f551694def69afee6fbe295bbe2d2 Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
This commit is contained in:
parent
d519b085d1
commit
c012ee2940
@ -2029,14 +2029,9 @@ void QObject::deleteLater()
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
const int flagged_locations_count = 2;
|
|
||||||
static const char* flagged_locations[flagged_locations_count] = {0};
|
|
||||||
|
|
||||||
const char *qFlagLocation(const char *method)
|
const char *qFlagLocation(const char *method)
|
||||||
{
|
{
|
||||||
static int idx = 0;
|
QThreadData::current()->flaggedSignatures.store(method);
|
||||||
flagged_locations[idx] = method;
|
|
||||||
idx = (idx+1) % flagged_locations_count;
|
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2048,14 +2043,11 @@ static int extract_code(const char *member)
|
|||||||
|
|
||||||
static const char * extract_location(const char *member)
|
static const char * extract_location(const char *member)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < flagged_locations_count; ++i) {
|
if (QThreadData::current()->flaggedSignatures.contains(member)) {
|
||||||
if (member == flagged_locations[i]) {
|
// signature includes location information after the first null-terminator
|
||||||
// signature includes location information after the first null-terminator
|
const char *location = member + qstrlen(member) + 1;
|
||||||
const char *location = member + qstrlen(member) + 1;
|
if (*location != '\0')
|
||||||
if (*location != '\0')
|
return location;
|
||||||
return location;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -242,6 +242,26 @@ public:
|
|||||||
return canWait;
|
return canWait;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This class provides per-thread (by way of being a QThreadData
|
||||||
|
// member) storage for qFlagLocation()
|
||||||
|
class FlaggedDebugSignatures
|
||||||
|
{
|
||||||
|
static const uint Count = 2;
|
||||||
|
|
||||||
|
uint idx;
|
||||||
|
const char* locations[Count];
|
||||||
|
|
||||||
|
public:
|
||||||
|
FlaggedDebugSignatures() : idx(0)
|
||||||
|
{ std::fill_n(locations, Count, static_cast<char*>(0)); }
|
||||||
|
|
||||||
|
void store(const char* method)
|
||||||
|
{ locations[idx++ % Count] = method; }
|
||||||
|
|
||||||
|
bool contains(const char *method) const
|
||||||
|
{ return std::find(locations, locations + Count, method) != locations + Count; }
|
||||||
|
};
|
||||||
|
|
||||||
QThread *thread;
|
QThread *thread;
|
||||||
Qt::HANDLE threadId;
|
Qt::HANDLE threadId;
|
||||||
bool quitNow;
|
bool quitNow;
|
||||||
@ -252,6 +272,7 @@ public:
|
|||||||
bool canWait;
|
bool canWait;
|
||||||
QVector<void *> tls;
|
QVector<void *> tls;
|
||||||
bool isAdopted;
|
bool isAdopted;
|
||||||
|
FlaggedDebugSignatures flaggedSignatures;
|
||||||
};
|
};
|
||||||
|
|
||||||
class QScopedLoopLevelCounter
|
class QScopedLoopLevelCounter
|
||||||
|
Loading…
x
Reference in New Issue
Block a user