mirror of
https://github.com/opencv/opencv.git
synced 2025-01-18 22:44:02 +08:00
Merge pull request #20841 from alalek:core_keep_TlsAbstraction_singleton_3.4
This commit is contained in:
commit
17bd9a1fa1
@ -53,6 +53,18 @@
|
||||
#include <opencv2/core/utils/tls.hpp>
|
||||
#include <opencv2/core/utils/instrumentation.hpp>
|
||||
|
||||
#ifndef OPENCV_WITH_THREAD_SANITIZER
|
||||
#if defined(__clang__) && defined(__has_feature)
|
||||
#if __has_feature(thread_sanitizer)
|
||||
#define OPENCV_WITH_THREAD_SANITIZER 1
|
||||
#include <atomic> // assume C++11
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifndef OPENCV_WITH_THREAD_SANITIZER
|
||||
#define OPENCV_WITH_THREAD_SANITIZER 0
|
||||
#endif
|
||||
|
||||
namespace cv {
|
||||
|
||||
static void _initSystem()
|
||||
@ -1426,74 +1438,75 @@ namespace details {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
class DisposedSingletonMark
|
||||
{
|
||||
private:
|
||||
static bool mark;
|
||||
protected:
|
||||
DisposedSingletonMark() {}
|
||||
~DisposedSingletonMark()
|
||||
{
|
||||
mark = true;
|
||||
}
|
||||
public:
|
||||
static bool isDisposed() { return mark; }
|
||||
};
|
||||
|
||||
// TLS platform abstraction layer
|
||||
class TlsAbstraction : public DisposedSingletonMark<TlsAbstraction>
|
||||
class TlsAbstraction
|
||||
{
|
||||
public:
|
||||
TlsAbstraction();
|
||||
~TlsAbstraction();
|
||||
void* getData() const
|
||||
~TlsAbstraction()
|
||||
{
|
||||
if (isDisposed()) // guard: static initialization order fiasco
|
||||
return NULL;
|
||||
return getData_();
|
||||
}
|
||||
void setData(void *pData)
|
||||
{
|
||||
if (isDisposed()) // guard: static initialization order fiasco
|
||||
return;
|
||||
return setData_(pData);
|
||||
// TlsAbstraction singleton should not be released
|
||||
// There is no reliable way to avoid problems caused by static initialization order fiasco
|
||||
// NB: Do NOT use logging here
|
||||
fprintf(stderr, "OpenCV FATAL: TlsAbstraction::~TlsAbstraction() call is not expected\n");
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
void* getData() const;
|
||||
void setData(void *pData);
|
||||
|
||||
void releaseSystemResources();
|
||||
|
||||
private:
|
||||
void* getData_() const;
|
||||
void setData_(void *pData);
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WINRT
|
||||
DWORD tlsKey;
|
||||
bool disposed;
|
||||
#endif
|
||||
#else // _WIN32
|
||||
pthread_key_t tlsKey;
|
||||
#if OPENCV_WITH_THREAD_SANITIZER
|
||||
std::atomic<bool> disposed;
|
||||
#else
|
||||
bool disposed;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
template<> bool DisposedSingletonMark<TlsAbstraction>::mark = false;
|
||||
|
||||
static TlsAbstraction& getTlsAbstraction_()
|
||||
class TlsAbstractionReleaseGuard
|
||||
{
|
||||
static TlsAbstraction g_tls; // disposed in atexit() handlers (required for unregistering our callbacks)
|
||||
return g_tls;
|
||||
}
|
||||
TlsAbstraction& tls_;
|
||||
public:
|
||||
TlsAbstractionReleaseGuard(TlsAbstraction& tls) : tls_(tls)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
~TlsAbstractionReleaseGuard()
|
||||
{
|
||||
tls_.releaseSystemResources();
|
||||
}
|
||||
};
|
||||
|
||||
// TODO use reference
|
||||
static TlsAbstraction* getTlsAbstraction()
|
||||
{
|
||||
#ifdef CV_CXX11
|
||||
static TlsAbstraction* instance = &getTlsAbstraction_();
|
||||
static TlsAbstraction *g_tls = new TlsAbstraction(); // memory leak is intended here to avoid disposing of TLS container
|
||||
static TlsAbstractionReleaseGuard g_tlsReleaseGuard(*g_tls);
|
||||
#else
|
||||
static TlsAbstraction* volatile instance = NULL;
|
||||
if (instance == NULL)
|
||||
static TlsAbstraction* volatile g_tls = NULL;
|
||||
if (g_tls == NULL)
|
||||
{
|
||||
cv::AutoLock lock(cv::getInitializationMutex());
|
||||
if (instance == NULL)
|
||||
instance = &getTlsAbstraction_();
|
||||
if (g_tls == NULL)
|
||||
{
|
||||
g_tls = new TlsAbstraction();
|
||||
static TlsAbstractionReleaseGuard g_tlsReleaseGuard(*g_tls);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return DisposedSingletonMark<TlsAbstraction>::isDisposed() ? NULL : instance;
|
||||
return g_tls;
|
||||
}
|
||||
|
||||
|
||||
@ -1501,12 +1514,15 @@ static TlsAbstraction* getTlsAbstraction()
|
||||
#ifdef WINRT
|
||||
static __declspec( thread ) void* tlsData = NULL; // using C++11 thread attribute for local thread data
|
||||
TlsAbstraction::TlsAbstraction() {}
|
||||
TlsAbstraction::~TlsAbstraction() {}
|
||||
void* TlsAbstraction::getData_() const
|
||||
void TlsAbstraction::releaseSystemResources()
|
||||
{
|
||||
cv::__termination = true; // DllMain is missing in static builds
|
||||
}
|
||||
void* TlsAbstraction::getData() const
|
||||
{
|
||||
return tlsData;
|
||||
}
|
||||
void TlsAbstraction::setData_(void *pData)
|
||||
void TlsAbstraction::setData(void *pData)
|
||||
{
|
||||
tlsData = pData;
|
||||
}
|
||||
@ -1515,6 +1531,7 @@ void TlsAbstraction::setData_(void *pData)
|
||||
static void NTAPI opencv_fls_destructor(void* pData);
|
||||
#endif // CV_USE_FLS
|
||||
TlsAbstraction::TlsAbstraction()
|
||||
: disposed(false)
|
||||
{
|
||||
#ifndef CV_USE_FLS
|
||||
tlsKey = TlsAlloc();
|
||||
@ -1523,8 +1540,10 @@ TlsAbstraction::TlsAbstraction()
|
||||
#endif // CV_USE_FLS
|
||||
CV_Assert(tlsKey != TLS_OUT_OF_INDEXES);
|
||||
}
|
||||
TlsAbstraction::~TlsAbstraction()
|
||||
void TlsAbstraction::releaseSystemResources()
|
||||
{
|
||||
cv::__termination = true; // DllMain is missing in static builds
|
||||
disposed = true;
|
||||
#ifndef CV_USE_FLS
|
||||
TlsFree(tlsKey);
|
||||
#else // CV_USE_FLS
|
||||
@ -1532,16 +1551,20 @@ TlsAbstraction::~TlsAbstraction()
|
||||
#endif // CV_USE_FLS
|
||||
tlsKey = TLS_OUT_OF_INDEXES;
|
||||
}
|
||||
void* TlsAbstraction::getData_() const
|
||||
void* TlsAbstraction::getData() const
|
||||
{
|
||||
if (disposed)
|
||||
return NULL;
|
||||
#ifndef CV_USE_FLS
|
||||
return TlsGetValue(tlsKey);
|
||||
#else // CV_USE_FLS
|
||||
return FlsGetValue(tlsKey);
|
||||
#endif // CV_USE_FLS
|
||||
}
|
||||
void TlsAbstraction::setData_(void *pData)
|
||||
void TlsAbstraction::setData(void *pData)
|
||||
{
|
||||
if (disposed)
|
||||
return; // no-op
|
||||
#ifndef CV_USE_FLS
|
||||
CV_Assert(TlsSetValue(tlsKey, pData) == TRUE);
|
||||
#else // CV_USE_FLS
|
||||
@ -1552,11 +1575,14 @@ void TlsAbstraction::setData_(void *pData)
|
||||
#else // _WIN32
|
||||
static void opencv_tls_destructor(void* pData);
|
||||
TlsAbstraction::TlsAbstraction()
|
||||
: disposed(false)
|
||||
{
|
||||
CV_Assert(pthread_key_create(&tlsKey, opencv_tls_destructor) == 0);
|
||||
}
|
||||
TlsAbstraction::~TlsAbstraction()
|
||||
void TlsAbstraction::releaseSystemResources()
|
||||
{
|
||||
cv::__termination = true; // DllMain is missing in static builds
|
||||
disposed = true;
|
||||
if (pthread_key_delete(tlsKey) != 0)
|
||||
{
|
||||
// Don't use logging here
|
||||
@ -1564,12 +1590,16 @@ TlsAbstraction::~TlsAbstraction()
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
void* TlsAbstraction::getData_() const
|
||||
void* TlsAbstraction::getData() const
|
||||
{
|
||||
if (disposed)
|
||||
return NULL;
|
||||
return pthread_getspecific(tlsKey);
|
||||
}
|
||||
void TlsAbstraction::setData_(void *pData)
|
||||
void TlsAbstraction::setData(void *pData)
|
||||
{
|
||||
if (disposed)
|
||||
return; // no-op
|
||||
CV_Assert(pthread_setspecific(tlsKey, pData) == 0);
|
||||
}
|
||||
#endif
|
||||
@ -1597,6 +1627,7 @@ public:
|
||||
TlsStorage() :
|
||||
tlsSlotsSize(0)
|
||||
{
|
||||
(void)getTlsAbstraction(); // ensure singeton initialization (for correct order of atexit calls)
|
||||
tlsSlots.reserve(32);
|
||||
threads.reserve(32);
|
||||
g_isTlsStorageInitialized = true;
|
||||
@ -1834,11 +1865,11 @@ static void WINAPI opencv_fls_destructor(void* pData)
|
||||
#endif // CV_USE_FLS
|
||||
#endif // _WIN32
|
||||
|
||||
static TlsAbstraction* const g_force_initialization_of_TlsAbstraction
|
||||
static TlsStorage* const g_force_initialization_of_TlsStorage
|
||||
#if defined __GNUC__
|
||||
__attribute__((unused))
|
||||
#endif
|
||||
= getTlsAbstraction();
|
||||
= &getTlsStorage();
|
||||
|
||||
} // namespace details
|
||||
using namespace details;
|
||||
|
Loading…
Reference in New Issue
Block a user