mirror of
https://github.com/opencv/opencv.git
synced 2024-11-24 19:20:28 +08:00
core(tls): unblock TlsAbstraction destructor call
- required to unregister callbacks from system
This commit is contained in:
parent
eb44e0a556
commit
818585fd12
@ -1408,16 +1408,44 @@ 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
|
||||
class TlsAbstraction : public DisposedSingletonMark<TlsAbstraction>
|
||||
{
|
||||
public:
|
||||
TlsAbstraction();
|
||||
~TlsAbstraction();
|
||||
void* GetData() const;
|
||||
void SetData(void *pData);
|
||||
void* getData() const
|
||||
{
|
||||
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:
|
||||
void* getData_() const;
|
||||
void setData_(void *pData);
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WINRT
|
||||
DWORD tlsKey;
|
||||
@ -1427,16 +1455,40 @@ private:
|
||||
#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 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::getData_() const
|
||||
{
|
||||
return tlsData;
|
||||
}
|
||||
void TlsAbstraction::SetData(void *pData)
|
||||
void TlsAbstraction::setData_(void *pData)
|
||||
{
|
||||
tlsData = pData;
|
||||
}
|
||||
@ -1460,8 +1512,9 @@ TlsAbstraction::~TlsAbstraction()
|
||||
#else // CV_USE_FLS
|
||||
FlsFree(tlsKey);
|
||||
#endif // CV_USE_FLS
|
||||
tlsKey = TLS_OUT_OF_INDEXES;
|
||||
}
|
||||
void* TlsAbstraction::GetData() const
|
||||
void* TlsAbstraction::getData_() const
|
||||
{
|
||||
#ifndef CV_USE_FLS
|
||||
return TlsGetValue(tlsKey);
|
||||
@ -1469,7 +1522,7 @@ void* TlsAbstraction::GetData() const
|
||||
return FlsGetValue(tlsKey);
|
||||
#endif // CV_USE_FLS
|
||||
}
|
||||
void TlsAbstraction::SetData(void *pData)
|
||||
void TlsAbstraction::setData_(void *pData)
|
||||
{
|
||||
#ifndef CV_USE_FLS
|
||||
CV_Assert(TlsSetValue(tlsKey, pData) == TRUE);
|
||||
@ -1486,13 +1539,18 @@ 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);
|
||||
}
|
||||
void TlsAbstraction::SetData(void *pData)
|
||||
void TlsAbstraction::setData_(void *pData)
|
||||
{
|
||||
CV_Assert(pthread_setspecific(tlsKey, pData) == 0);
|
||||
}
|
||||
@ -1525,12 +1583,17 @@ public:
|
||||
{
|
||||
// TlsStorage object should not be released
|
||||
// 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)
|
||||
{
|
||||
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)
|
||||
return; // no OpenCV TLS data for this thread
|
||||
AutoLock guard(mtxGlobalAccess);
|
||||
@ -1540,7 +1603,7 @@ public:
|
||||
{
|
||||
threads[i] = NULL;
|
||||
if (tlsValue == NULL)
|
||||
tls.SetData(0);
|
||||
tls->setData(0);
|
||||
std::vector<void*>& thread_slots = pTD->slots;
|
||||
for (size_t slotIdx = 0; slotIdx < thread_slots.size(); slotIdx++)
|
||||
{
|
||||
@ -1552,13 +1615,16 @@ public:
|
||||
if (container)
|
||||
container->deleteDataInstance(pData);
|
||||
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;
|
||||
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
|
||||
@ -1615,7 +1681,11 @@ public:
|
||||
CV_Assert(tlsSlotsSize > slotIdx);
|
||||
#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)
|
||||
return threadData->slots[slotIdx];
|
||||
|
||||
@ -1647,11 +1717,15 @@ public:
|
||||
CV_Assert(tlsSlotsSize > slotIdx);
|
||||
#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)
|
||||
{
|
||||
threadData = new ThreadData;
|
||||
tls.SetData((void*)threadData);
|
||||
tls->setData((void*)threadData);
|
||||
{
|
||||
AutoLock guard(mtxGlobalAccess);
|
||||
|
||||
@ -1686,8 +1760,6 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
TlsAbstraction tls; // TLS abstraction layer instance
|
||||
|
||||
Mutex mtxGlobalAccess; // Shared objects operation guard
|
||||
size_t tlsSlotsSize; // equal to tlsSlots.size() in synchronized sections
|
||||
// without synchronization this counter doesn't decrease - it is used for slotIdx sanity checks
|
||||
|
Loading…
Reference in New Issue
Block a user