core(tls): avoid destruction of TlsAbstraction singleton

pull/20841/head
Alexander Alekhin 3 years ago
parent a3d7811f24
commit 4985311d46
  1. 135
      modules/core/src/system.cpp

@ -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…
Cancel
Save