Make the named QColorSpace constructor thread-safe

Avoid accessing the shared pointer table without using atomic.

Cleans up the shared table on exit for leak tracking utilities.

Pick-to: 5.15
Change-Id: Ia2d6d79dea1c8be02bae2d8111e290f49eedf409
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
This commit is contained in:
Allan Sandfeld Jensen 2020-10-02 16:33:33 +02:00
parent 1613eff15e
commit cd0b5bba9a

View File

@ -46,6 +46,7 @@
#include "qcolortransform_p.h"
#include "qicc_p.h"
#include <qatomic.h>
#include <qmath.h>
#include <qtransform.h>
@ -55,6 +56,18 @@ QT_BEGIN_NAMESPACE
QBasicMutex QColorSpacePrivate::s_lutWriteLock;
static QAtomicPointer<QColorSpacePrivate> s_predefinedColorspacePrivates[QColorSpace::ProPhotoRgb] = {};
static void cleanupPredefinedColorspaces()
{
for (QAtomicPointer<QColorSpacePrivate> &ptr : s_predefinedColorspacePrivates) {
QColorSpacePrivate *prv = ptr.fetchAndStoreAcquire(nullptr);
if (prv && !prv->ref.deref())
delete prv;
}
}
Q_DESTRUCTOR_FUNCTION(cleanupPredefinedColorspaces)
QColorSpacePrimaries::QColorSpacePrimaries(QColorSpace::Primaries primaries)
{
switch (primaries) {
@ -426,12 +439,18 @@ QColorSpace::QColorSpace(NamedColorSpace namedColorSpace)
qWarning() << "QColorSpace attempted constructed from invalid QColorSpace::NamedColorSpace: " << int(namedColorSpace);
return;
}
static QColorSpacePrivate *predefinedColorspacePrivates[QColorSpace::ProPhotoRgb + 1];
if (!predefinedColorspacePrivates[namedColorSpace]) {
predefinedColorspacePrivates[namedColorSpace] = new QColorSpacePrivate(namedColorSpace);
predefinedColorspacePrivates[namedColorSpace]->ref.ref();
// The defined namespaces start at 1:
auto &atomicRef = s_predefinedColorspacePrivates[static_cast<int>(namedColorSpace) - 1];
QColorSpacePrivate *cspriv = atomicRef.loadAcquire();
if (!cspriv) {
auto *tmp = new QColorSpacePrivate(namedColorSpace);
tmp->ref.ref();
if (atomicRef.testAndSetOrdered(nullptr, tmp, cspriv))
cspriv = tmp;
else
delete tmp;
}
d_ptr = predefinedColorspacePrivates[namedColorSpace];
d_ptr = cspriv;
d_ptr->ref.ref();
Q_ASSERT(isValid());
}