From a118577a57a8807bb2d99676fd97f65e937e2c44 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 11 Dec 2013 18:49:13 +0400 Subject: [PATCH] core: added TLS support --- modules/core/include/opencv2/core/core.hpp | 26 ++++ modules/core/src/system.cpp | 235 ++++++++++++++++++++++++++--- 2 files changed, 243 insertions(+), 18 deletions(-) diff --git a/modules/core/include/opencv2/core/core.hpp b/modules/core/include/opencv2/core/core.hpp index b6426d8..cafba0f 100644 --- a/modules/core/include/opencv2/core/core.hpp +++ b/modules/core/include/opencv2/core/core.hpp @@ -4821,6 +4821,32 @@ private: 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 +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 diff --git a/modules/core/src/system.cpp b/modules/core/src/system.cpp index 88f13d6..b301d95 100644 --- a/modules/core/src/system.cpp +++ b/modules/core/src/system.cpp @@ -806,24 +806,6 @@ cvGetModuleInfo( const char* name, const char **version, const char **plugin_lis *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 { @@ -941,6 +923,223 @@ void Mutex::lock() { impl->lock(); } void Mutex::unlock() { impl->unlock(); } bool Mutex::trylock() { return impl->trylock(); } + +//////////////////////////////// thread-local storage //////////////////////////////// + +class TLSStorage +{ + std::vector 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 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. */ -- 2.7.4