core: added TLS support
This commit is contained in:
parent
ce503c64bf
commit
a118577a57
@ -4821,6 +4821,32 @@ private:
|
|||||||
AutoLock& operator = (const AutoLock&);
|
AutoLock& operator = (const AutoLock&);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TLSDataContainer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int key_;
|
||||||
|
protected:
|
||||||
|
CV_EXPORTS TLSDataContainer();
|
||||||
|
CV_EXPORTS ~TLSDataContainer(); // virtual is not required
|
||||||
|
public:
|
||||||
|
virtual void* createDataInstance() const = 0;
|
||||||
|
virtual void deleteDataInstance(void* data) const = 0;
|
||||||
|
|
||||||
|
CV_EXPORTS void* getData() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class TLSData : protected TLSDataContainer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline TLSData() {}
|
||||||
|
inline ~TLSData() {}
|
||||||
|
inline T* get() const { return (T*)getData(); }
|
||||||
|
private:
|
||||||
|
virtual void* createDataInstance() const { return new T; }
|
||||||
|
virtual void deleteDataInstance(void* data) const { delete (T*)data; }
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
@ -806,24 +806,6 @@ cvGetModuleInfo( const char* name, const char **version, const char **plugin_lis
|
|||||||
*plugin_list = plugin_list_buf;
|
*plugin_list = plugin_list_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined CVAPI_EXPORTS && defined WIN32 && !defined WINCE
|
|
||||||
#ifdef HAVE_WINRT
|
|
||||||
#pragma warning(disable:4447) // Disable warning 'main' signature found without threading model
|
|
||||||
#endif
|
|
||||||
|
|
||||||
BOOL WINAPI DllMain( HINSTANCE, DWORD fdwReason, LPVOID );
|
|
||||||
|
|
||||||
BOOL WINAPI DllMain( HINSTANCE, DWORD fdwReason, LPVOID )
|
|
||||||
{
|
|
||||||
if( fdwReason == DLL_THREAD_DETACH || fdwReason == DLL_PROCESS_DETACH )
|
|
||||||
{
|
|
||||||
cv::deleteThreadAllocData();
|
|
||||||
cv::deleteThreadRNGData();
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace cv
|
namespace cv
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -941,6 +923,223 @@ void Mutex::lock() { impl->lock(); }
|
|||||||
void Mutex::unlock() { impl->unlock(); }
|
void Mutex::unlock() { impl->unlock(); }
|
||||||
bool Mutex::trylock() { return impl->trylock(); }
|
bool Mutex::trylock() { return impl->trylock(); }
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////// thread-local storage ////////////////////////////////
|
||||||
|
|
||||||
|
class TLSStorage
|
||||||
|
{
|
||||||
|
std::vector<void*> tlsData_;
|
||||||
|
public:
|
||||||
|
TLSStorage() { tlsData_.reserve(16); }
|
||||||
|
~TLSStorage();
|
||||||
|
inline void* getData(int key) const
|
||||||
|
{
|
||||||
|
CV_DbgAssert(key >= 0);
|
||||||
|
return (key < (int)tlsData_.size()) ? tlsData_[key] : NULL;
|
||||||
|
}
|
||||||
|
inline void setData(int key, void* data)
|
||||||
|
{
|
||||||
|
CV_DbgAssert(key >= 0);
|
||||||
|
if (key >= (int)tlsData_.size())
|
||||||
|
{
|
||||||
|
tlsData_.resize(key + 1, NULL);
|
||||||
|
}
|
||||||
|
tlsData_[key] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static TLSStorage* get();
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#pragma warning(disable:4505) // unreferenced local function has been removed
|
||||||
|
|
||||||
|
#ifdef HAVE_WINRT
|
||||||
|
// using C++11 thread attribute for local thread data
|
||||||
|
static __declspec( thread ) TLSStorage* g_tlsdata = NULL;
|
||||||
|
|
||||||
|
static void deleteThreadData()
|
||||||
|
{
|
||||||
|
if (g_tlsdata)
|
||||||
|
{
|
||||||
|
delete g_tlsdata;
|
||||||
|
g_tlsdata = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TLSStorage* TLSStorage::get()
|
||||||
|
{
|
||||||
|
if (!g_tlsdata)
|
||||||
|
{
|
||||||
|
g_tlsdata = new TLSStorage;
|
||||||
|
}
|
||||||
|
return g_tlsdata;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#ifdef WINCE
|
||||||
|
# define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF)
|
||||||
|
#endif
|
||||||
|
static DWORD tlsKey = TLS_OUT_OF_INDEXES;
|
||||||
|
|
||||||
|
static void deleteThreadData()
|
||||||
|
{
|
||||||
|
if(tlsKey != TLS_OUT_OF_INDEXES)
|
||||||
|
{
|
||||||
|
delete (TLSStorage*)TlsGetValue(tlsKey);
|
||||||
|
TlsSetValue(tlsKey, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TLSStorage* TLSStorage::get()
|
||||||
|
{
|
||||||
|
if (tlsKey == TLS_OUT_OF_INDEXES)
|
||||||
|
{
|
||||||
|
tlsKey = TlsAlloc();
|
||||||
|
CV_Assert(tlsKey != TLS_OUT_OF_INDEXES);
|
||||||
|
}
|
||||||
|
TLSStorage* d = (TLSStorage*)TlsGetValue(tlsKey);
|
||||||
|
if (!d)
|
||||||
|
{
|
||||||
|
d = new TLSStorage;
|
||||||
|
TlsSetValue(tlsKey, d);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
#endif //HAVE_WINRT
|
||||||
|
|
||||||
|
#if defined CVAPI_EXPORTS && defined WIN32 && !defined WINCE
|
||||||
|
#ifdef HAVE_WINRT
|
||||||
|
#pragma warning(disable:4447) // Disable warning 'main' signature found without threading model
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE, DWORD fdwReason, LPVOID);
|
||||||
|
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE, DWORD fdwReason, LPVOID)
|
||||||
|
{
|
||||||
|
if (fdwReason == DLL_THREAD_DETACH || fdwReason == DLL_PROCESS_DETACH)
|
||||||
|
{
|
||||||
|
cv::deleteThreadAllocData();
|
||||||
|
cv::deleteThreadRNGData();
|
||||||
|
cv::deleteThreadData();
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
static pthread_key_t tlsKey = 0;
|
||||||
|
static pthread_once_t tlsKeyOnce = PTHREAD_ONCE_INIT;
|
||||||
|
|
||||||
|
static void deleteTLSStorage(void* data)
|
||||||
|
{
|
||||||
|
delete (TLSStorage*)data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void makeKey()
|
||||||
|
{
|
||||||
|
int errcode = pthread_key_create(&tlsKey, deleteTLSStorage);
|
||||||
|
CV_Assert(errcode == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TLSStorage* TLSStorage::get()
|
||||||
|
{
|
||||||
|
pthread_once(&tlsKeyOnce, makeKey);
|
||||||
|
TLSStorage* d = (TLSStorage*)pthread_getspecific(tlsKey);
|
||||||
|
if( !d )
|
||||||
|
{
|
||||||
|
d = new TLSStorage;
|
||||||
|
pthread_setspecific(tlsKey, d);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class TLSContainerStorage
|
||||||
|
{
|
||||||
|
cv::Mutex mutex_;
|
||||||
|
std::vector<TLSDataContainer*> tlsContainers_;
|
||||||
|
public:
|
||||||
|
TLSContainerStorage() { }
|
||||||
|
~TLSContainerStorage()
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < tlsContainers_.size(); i++)
|
||||||
|
{
|
||||||
|
CV_DbgAssert(tlsContainers_[i] == NULL); // not all keys released
|
||||||
|
tlsContainers_[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int allocateKey(TLSDataContainer* pContainer)
|
||||||
|
{
|
||||||
|
cv::AutoLock lock(mutex_);
|
||||||
|
tlsContainers_.push_back(pContainer);
|
||||||
|
return (int)tlsContainers_.size() - 1;
|
||||||
|
}
|
||||||
|
void releaseKey(int id, TLSDataContainer* pContainer)
|
||||||
|
{
|
||||||
|
cv::AutoLock lock(mutex_);
|
||||||
|
CV_Assert(tlsContainers_[id] == pContainer);
|
||||||
|
tlsContainers_[id] = NULL;
|
||||||
|
// currently, we don't go into thread's TLSData and release data for this key
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroyData(int key, void* data)
|
||||||
|
{
|
||||||
|
cv::AutoLock lock(mutex_);
|
||||||
|
TLSDataContainer* k = tlsContainers_[key];
|
||||||
|
if (!k)
|
||||||
|
return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
k->deleteDataInstance(data);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
CV_DbgAssert(k == NULL); // Debug this!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static TLSContainerStorage tlsContainerStorage;
|
||||||
|
|
||||||
|
TLSDataContainer::TLSDataContainer()
|
||||||
|
: key_(-1)
|
||||||
|
{
|
||||||
|
key_ = tlsContainerStorage.allocateKey(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TLSDataContainer::~TLSDataContainer()
|
||||||
|
{
|
||||||
|
tlsContainerStorage.releaseKey(key_, this);
|
||||||
|
key_ = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* TLSDataContainer::getData() const
|
||||||
|
{
|
||||||
|
CV_Assert(key_ >= 0);
|
||||||
|
TLSStorage* tlsData = TLSStorage::get();
|
||||||
|
void* data = tlsData->getData(key_);
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
data = this->createDataInstance();
|
||||||
|
CV_DbgAssert(data != NULL);
|
||||||
|
tlsData->setData(key_, data);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
TLSStorage::~TLSStorage()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (int)tlsData_.size(); i++)
|
||||||
|
{
|
||||||
|
void*& data = tlsData_[i];
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
tlsContainerStorage.destroyData(i, data);
|
||||||
|
data = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tlsData_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cv
|
||||||
|
|
||||||
/* End of file. */
|
/* End of file. */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user