Commit 818585fd authored by Alexander Alekhin's avatar Alexander Alekhin

core(tls): unblock TlsAbstraction destructor call

- required to unregister callbacks from system
parent eb44e0a5
...@@ -1408,16 +1408,44 @@ namespace details { ...@@ -1408,16 +1408,44 @@ namespace details {
#endif #endif
#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 // TLS platform abstraction layer
class TlsAbstraction class TlsAbstraction : public DisposedSingletonMark<TlsAbstraction>
{ {
public: public:
TlsAbstraction(); TlsAbstraction();
~TlsAbstraction(); ~TlsAbstraction();
void* GetData() const; void* getData() const
void SetData(void *pData); {
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);
}
private: private:
void* getData_() const;
void setData_(void *pData);
#ifdef _WIN32 #ifdef _WIN32
#ifndef WINRT #ifndef WINRT
DWORD tlsKey; DWORD tlsKey;
...@@ -1427,16 +1455,40 @@ private: ...@@ -1427,16 +1455,40 @@ private:
#endif #endif
}; };
template<> bool DisposedSingletonMark<TlsAbstraction>::mark = false;
static TlsAbstraction& getTlsAbstraction_()
{
static TlsAbstraction g_tls; // disposed in atexit() handlers (required for unregistering our callbacks)
return g_tls;
}
static TlsAbstraction* getTlsAbstraction()
{
#ifdef CV_CXX11
static TlsAbstraction* instance = &getTlsAbstraction_();
#else
static TlsAbstraction* volatile instance = NULL;
if (instance == NULL)
{
cv::AutoLock lock(cv::getInitializationMutex());
if (instance == NULL)
instance = &getTlsAbstraction_();
}
#endif
return DisposedSingletonMark<TlsAbstraction>::isDisposed() ? NULL : instance;
}
#ifdef _WIN32 #ifdef _WIN32
#ifdef WINRT #ifdef WINRT
static __declspec( thread ) void* tlsData = NULL; // using C++11 thread attribute for local thread data static __declspec( thread ) void* tlsData = NULL; // using C++11 thread attribute for local thread data
TlsAbstraction::TlsAbstraction() {} TlsAbstraction::TlsAbstraction() {}
TlsAbstraction::~TlsAbstraction() {} TlsAbstraction::~TlsAbstraction() {}
void* TlsAbstraction::GetData() const void* TlsAbstraction::getData_() const
{ {
return tlsData; return tlsData;
} }
void TlsAbstraction::SetData(void *pData) void TlsAbstraction::setData_(void *pData)
{ {
tlsData = pData; tlsData = pData;
} }
...@@ -1460,8 +1512,9 @@ TlsAbstraction::~TlsAbstraction() ...@@ -1460,8 +1512,9 @@ TlsAbstraction::~TlsAbstraction()
#else // CV_USE_FLS #else // CV_USE_FLS
FlsFree(tlsKey); FlsFree(tlsKey);
#endif // CV_USE_FLS #endif // CV_USE_FLS
tlsKey = TLS_OUT_OF_INDEXES;
} }
void* TlsAbstraction::GetData() const void* TlsAbstraction::getData_() const
{ {
#ifndef CV_USE_FLS #ifndef CV_USE_FLS
return TlsGetValue(tlsKey); return TlsGetValue(tlsKey);
...@@ -1469,7 +1522,7 @@ void* TlsAbstraction::GetData() const ...@@ -1469,7 +1522,7 @@ void* TlsAbstraction::GetData() const
return FlsGetValue(tlsKey); return FlsGetValue(tlsKey);
#endif // CV_USE_FLS #endif // CV_USE_FLS
} }
void TlsAbstraction::SetData(void *pData) void TlsAbstraction::setData_(void *pData)
{ {
#ifndef CV_USE_FLS #ifndef CV_USE_FLS
CV_Assert(TlsSetValue(tlsKey, pData) == TRUE); CV_Assert(TlsSetValue(tlsKey, pData) == TRUE);
...@@ -1486,13 +1539,18 @@ TlsAbstraction::TlsAbstraction() ...@@ -1486,13 +1539,18 @@ TlsAbstraction::TlsAbstraction()
} }
TlsAbstraction::~TlsAbstraction() TlsAbstraction::~TlsAbstraction()
{ {
CV_Assert(pthread_key_delete(tlsKey) == 0); if (pthread_key_delete(tlsKey) != 0)
{
// Don't use logging here
fprintf(stderr, "OpenCV ERROR: TlsAbstraction::~TlsAbstraction(): pthread_key_delete() call failed\n");
fflush(stderr);
}
} }
void* TlsAbstraction::GetData() const void* TlsAbstraction::getData_() const
{ {
return pthread_getspecific(tlsKey); return pthread_getspecific(tlsKey);
} }
void TlsAbstraction::SetData(void *pData) void TlsAbstraction::setData_(void *pData)
{ {
CV_Assert(pthread_setspecific(tlsKey, pData) == 0); CV_Assert(pthread_setspecific(tlsKey, pData) == 0);
} }
...@@ -1525,12 +1583,17 @@ public: ...@@ -1525,12 +1583,17 @@ public:
{ {
// TlsStorage object should not be released // TlsStorage object should not be released
// There is no reliable way to avoid problems caused by static initialization order fiasco // There is no reliable way to avoid problems caused by static initialization order fiasco
CV_LOG_FATAL(NULL, "TlsStorage::~TlsStorage() call is not expected"); // Don't use logging here
fprintf(stderr, "OpenCV FATAL: TlsStorage::~TlsStorage() call is not expected\n");
fflush(stderr);
} }
void releaseThread(void* tlsValue = NULL) void releaseThread(void* tlsValue = NULL)
{ {
ThreadData *pTD = tlsValue == NULL ? (ThreadData*)tls.GetData() : (ThreadData*)tlsValue; TlsAbstraction* tls = getTlsAbstraction();
if (NULL == tls)
return; // TLS signleton is not available (terminated)
ThreadData *pTD = tlsValue == NULL ? (ThreadData*)tls->getData() : (ThreadData*)tlsValue;
if (pTD == NULL) if (pTD == NULL)
return; // no OpenCV TLS data for this thread return; // no OpenCV TLS data for this thread
AutoLock guard(mtxGlobalAccess); AutoLock guard(mtxGlobalAccess);
...@@ -1540,7 +1603,7 @@ public: ...@@ -1540,7 +1603,7 @@ public:
{ {
threads[i] = NULL; threads[i] = NULL;
if (tlsValue == NULL) if (tlsValue == NULL)
tls.SetData(0); tls->setData(0);
std::vector<void*>& thread_slots = pTD->slots; std::vector<void*>& thread_slots = pTD->slots;
for (size_t slotIdx = 0; slotIdx < thread_slots.size(); slotIdx++) for (size_t slotIdx = 0; slotIdx < thread_slots.size(); slotIdx++)
{ {
...@@ -1552,13 +1615,16 @@ public: ...@@ -1552,13 +1615,16 @@ public:
if (container) if (container)
container->deleteDataInstance(pData); container->deleteDataInstance(pData);
else else
CV_LOG_ERROR(NULL, "TLS: container for slotIdx=" << slotIdx << " is NULL. Can't release thread data"); {
fprintf(stderr, "OpenCV ERROR: TLS: container for slotIdx=%d is NULL. Can't release thread data\n", (int)slotIdx);
fflush(stderr);
}
} }
delete pTD; delete pTD;
return; return;
} }
} }
CV_LOG_WARNING(NULL, "TLS: Can't release thread TLS data (unknown pointer or data race): " << (void*)pTD); fprintf(stderr, "OpenCV WARNING: TLS: Can't release thread TLS data (unknown pointer or data race): %p\n", (void*)pTD); fflush(stderr);
} }
// Reserve TLS storage index // Reserve TLS storage index
...@@ -1615,7 +1681,11 @@ public: ...@@ -1615,7 +1681,11 @@ public:
CV_Assert(tlsSlotsSize > slotIdx); CV_Assert(tlsSlotsSize > slotIdx);
#endif #endif
ThreadData* threadData = (ThreadData*)tls.GetData(); TlsAbstraction* tls = getTlsAbstraction();
if (NULL == tls)
return NULL; // TLS signleton is not available (terminated)
ThreadData* threadData = (ThreadData*)tls->getData();
if(threadData && threadData->slots.size() > slotIdx) if(threadData && threadData->slots.size() > slotIdx)
return threadData->slots[slotIdx]; return threadData->slots[slotIdx];
...@@ -1647,11 +1717,15 @@ public: ...@@ -1647,11 +1717,15 @@ public:
CV_Assert(tlsSlotsSize > slotIdx); CV_Assert(tlsSlotsSize > slotIdx);
#endif #endif
ThreadData* threadData = (ThreadData*)tls.GetData(); TlsAbstraction* tls = getTlsAbstraction();
if (NULL == tls)
return; // TLS signleton is not available (terminated)
ThreadData* threadData = (ThreadData*)tls->getData();
if(!threadData) if(!threadData)
{ {
threadData = new ThreadData; threadData = new ThreadData;
tls.SetData((void*)threadData); tls->setData((void*)threadData);
{ {
AutoLock guard(mtxGlobalAccess); AutoLock guard(mtxGlobalAccess);
...@@ -1686,8 +1760,6 @@ public: ...@@ -1686,8 +1760,6 @@ public:
} }
private: private:
TlsAbstraction tls; // TLS abstraction layer instance
Mutex mtxGlobalAccess; // Shared objects operation guard Mutex mtxGlobalAccess; // Shared objects operation guard
size_t tlsSlotsSize; // equal to tlsSlots.size() in synchronized sections size_t tlsSlotsSize; // equal to tlsSlots.size() in synchronized sections
// without synchronization this counter doesn't decrease - it is used for slotIdx sanity checks // without synchronization this counter doesn't decrease - it is used for slotIdx sanity checks
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment