Bug report #17351
Link failure on OS without thread local storage
Status: | Closed | ||
---|---|---|---|
Priority: | Normal | ||
Assignee: | Nyall Dawson | ||
Category: | Projection Support | ||
Affected QGIS version: | master | Regression?: | Yes |
Operating System: | OpenBSD | Easy fix?: | No |
Pull Request or Patch supplied: | No | Resolution: | |
Crashes QGIS or corrupts data: | No | Copied to github as #: | 25248 |
Description
OpenBSD doesnt have support (yet) for thread local storage, so since https://github.com/qgis/QGIS/pull/4561 the linking will fail.
Is there an alternative to use thread_local here ?
Associated revisions
Don't use thread_local on mingw or OpenBSD builds
MingW has broken support for thread_local, so force disabling it
see
https://sourceforge.net/p/mingw-w64/bugs/445/
https://sourceforge.net/p/mingw-w64/bugs/527/
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80816
also OpenBSD has no thread_local support, see https://issues.qgis.org/issues/17351
So on these platforms we fall back to using QThreadStorage.
Fixes #17351
History
#1 Updated by Nyall Dawson about 7 years ago
You may have luck by ifdefing in QThreadStorage for bsd. This is what's used in the 2.18 backport - see af3370d03e7e7502e8a738d99cd99e38df23768d
#2 Updated by landry Landry Breuil about 7 years ago
I have a bit of a hard time diffing the commits in 2.18 and master for that feature - you mean just replacing thread_local by QThreadStorage ? ie thread_local QgsProjContextStore replaced by QThreadStorage< QgsProjContextStore* > ?
#3 Updated by Nyall Dawson about 7 years ago
I can't recall if that was the only change required, but I'd start with that and see if it compiles OK and the transform related unit tests pass.
#4 Updated by landry Landry Breuil about 7 years ago
I probably need a bit more:
- static thread_local QgsProjContextStore mProjContext; + static QThreadStorage< QgsProjContextStore* > mProjContext;
Yields:
src/core/qgscoordinatetransform_p.cpp:188:139: error: no member named 'get' in 'QThreadStorage<QgsProjContextStore *>' QMap < uintptr_t, QPair< projPJ, projPJ > >::const_iterator it = mProjProjections.constFind( reinterpret_cast< uintptr_t>( mProjContext.get() ) );
I'll try to look a bit more at the 2.18 code.
Edit: hah, seems QThreadStorage needs to wrap the calls into .localData() to access the stored pointer. Right ?
#5 Updated by landry Landry Breuil about 7 years ago
Alas, with the following blind patch
Index: src/core/qgscoordinatetransform_p.h --- src/core/qgscoordinatetransform_p.h.orig +++ src/core/qgscoordinatetransform_p.h @@ -31,6 +31,7 @@ // #include <QSharedData> +#include <QThreadStorage> #include "qgscoordinatereferencesystem.h" typedef void *projPJ; @@ -100,7 +101,7 @@ class QgsCoordinateTransformPrivate : public QSharedDa * Thread local proj context storage. A new proj context will be created * for every thread. */ - static thread_local QgsProjContextStore mProjContext; + static QThreadStorage< QgsProjContextStore* > mProjContext; QReadWriteLock mProjLock; QMap < uintptr_t, QPair< projPJ, projPJ > > mProjProjections; Index: src/core/qgscoordinatetransform_p.cpp --- src/core/qgscoordinatetransform_p.cpp.orig +++ src/core/qgscoordinatetransform_p.cpp @@ -29,7 +29,7 @@ extern "C" /// @cond PRIVATE -thread_local QgsProjContextStore QgsCoordinateTransformPrivate::mProjContext; +QThreadStorage< QgsProjContextStore* > QgsCoordinateTransformPrivate::mProjContext; QgsProjContextStore::QgsProjContextStore() { @@ -185,7 +185,7 @@ QPair<projPJ, projPJ> QgsCoordinateTransformPrivate::t { mProjLock.lockForRead(); - QMap < uintptr_t, QPair< projPJ, projPJ > >::const_iterator it = mProjProjections.constFind( reinterpret_cast< uintptr_t>( mProjContext.get() ) ); + QMap < uintptr_t, QPair< projPJ, projPJ > >::const_iterator it = mProjProjections.constFind( reinterpret_cast< uintptr_t>( mProjContext.localData()->get() ) ); if ( it != mProjProjections.constEnd() ) { QPair<projPJ, projPJ> res = it.value(); @@ -196,9 +196,9 @@ QPair<projPJ, projPJ> QgsCoordinateTransformPrivate::t // proj projections don't exist yet, so we need to create mProjLock.unlock(); mProjLock.lockForWrite(); - QPair<projPJ, projPJ> res = qMakePair( pj_init_plus_ctx( mProjContext.get(), mSourceProjString.toUtf8() ), - pj_init_plus_ctx( mProjContext.get(), mDestProjString.toUtf8() ) ); - mProjProjections.insert( reinterpret_cast< uintptr_t>( mProjContext.get() ), res ); + QPair<projPJ, projPJ> res = qMakePair( pj_init_plus_ctx( mProjContext.localData()->get(), mSourceProjString.toUtf8() ), + pj_init_plus_ctx( mProjContext.localData()->get(), mDestProjString.toUtf8() ) ); + mProjProjections.insert( reinterpret_cast< uintptr_t>( mProjContext.localData()->get() ), res ); mProjLock.unlock(); return res;
at runtime it blows.
#0 QgsProjContextStore::get (this=0x0) at /usr/obj/ports/qgis-2.99pre0/QGIS-a843df8947b3597118ad162eb0c7263469e2f1b2/src/core/qgscoordinatetransform_p.h:52
#1 QgsCoordinateTransformPrivate::threadLocalProjData (this=0x1dc74ecacb80)
at /usr/obj/ports/qgis-2.99pre0/QGIS-a843df8947b3597118ad162eb0c7263469e2f1b2/src/core/qgscoordinatetransform_p.cpp:199
#2 0x00001dc735cce7cc in QgsCoordinateTransformPrivate::initialize (this=0x1dc74ecacb80)
at /usr/obj/ports/qgis-2.99pre0/QGIS-a843df8947b3597118ad162eb0c7263469e2f1b2/src/core/qgscoordinatetransform_p.cpp:131
#3 0x00001dc7288c9e53 in QgsMeasureDialog::updateSettings (this=0x1dc7d6613a00)
at /usr/obj/ports/qgis-2.99pre0/QGIS-a843df8947b3597118ad162eb0c7263469e2f1b2/src/app/qgsmeasuredialog.cpp:108
#4 0x00001dc7288d02fc in QgsMeasureTool::updateSettings (this=0x1dc7fe5fd700)
at /usr/obj/ports/qgis-2.99pre0/QGIS-a843df8947b3597118ad162eb0c7263469e2f1b2/src/app/qgsmeasuretool.cpp:163
#5 0x00001dc7246971e4 in QMetaObject::activate(QObject*, int, int, void**) () from /usr/local/lib/qt5/./libQt5Core.so.2.2
#6 Updated by Nyall Dawson about 7 years ago
Does 2.18.13 work ok? Maybe QThreadStorage doesn't work on bsd either...
#7 Updated by Nyall Dawson about 7 years ago
Actually you're missing bits:
QPair<projPJ, projPJ> QgsCoordinateTransform::threadLocalProjData() const
{
mProjLock.lockForRead();
projCtx pContext = nullptr;
if ( mProjContext.hasLocalData() )
pContext = mProjContext.localData()->get();
else
{
mProjContext.setLocalData( new QgsProjContextStore() );
pContext = mProjContext.localData()->get();
}
QMap < uintptr_t, QPair< projPJ, projPJ > >::const_iterator it = mProjProjections.constFind( reinterpret_cast< uintptr_t>( pContext ) );
...
QPair<projPJ, projPJ> res = qMakePair( pj_init_plus_ctx( pContext, mSourceProjString.toUtf8() ),
pj_init_plus_ctx( pContext, mDestProjString.toUtf8() ) );
mProjProjections.insert( reinterpret_cast< uintptr_t>( pContext ), res );
(untested - may be some other changes required)
#8 Updated by Nyall Dawson about 7 years ago
PR and discussion at https://github.com/qgis/QGIS/pull/5504
#9 Updated by landry Landry Breuil about 7 years ago
Nyall Dawson wrote:
Does 2.18.13 work ok? Maybe QThreadStorage doesn't work on bsd either...
2.18.13 & 14 work fine on OpenBSD.
#10 Updated by Nyall Dawson about 7 years ago
Updated PR at https://github.com/qgis/QGIS/pull/5541
#11 Updated by Nyall Dawson about 7 years ago
- % Done changed from 0 to 100
- Status changed from Open to Closed
Applied in changeset qgis|265be41d7c1cb0bb9d39aac3285c2c8fb40ffa47.