|
|
|
@ -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
|
|
|
|
|