TLS keys leak fix;

Disables TLS copy constructor and operator, as they can lead to errors and reservation of too much keys in TLS storage;

gather method was added to TLS to gather data from all threads;
This commit is contained in:
Pavel Vlasov 2015-09-16 14:00:36 +03:00
parent 9533982729
commit aa485ccd75
2 changed files with 57 additions and 11 deletions

View File

@ -520,6 +520,7 @@ protected:
TLSDataContainer(); TLSDataContainer();
virtual ~TLSDataContainer(); virtual ~TLSDataContainer();
void gatherData(std::vector<void*> &data) const;
#if OPENCV_ABI_COMPATIBILITY > 300 #if OPENCV_ABI_COMPATIBILITY > 300
void* getData() const; void* getData() const;
void release(); void release();
@ -546,9 +547,20 @@ public:
inline ~TLSData() { release(); } // Release key and delete associated data inline ~TLSData() { release(); } // Release key and delete associated data
inline T* get() const { return (T*)getData(); } // Get data assosiated with key inline T* get() const { return (T*)getData(); } // Get data assosiated with key
// Get data from all threads
inline void gather(std::vector<T*> &data) const
{
std::vector<void*> &dataVoid = reinterpret_cast<std::vector<void*>&>(data);
gatherData(dataVoid);
}
private: private:
virtual void* createDataInstance() const {return new T;} // Wrapper to allocate data by template virtual void* createDataInstance() const {return new T;} // Wrapper to allocate data by template
virtual void deleteDataInstance(void* pData) const {delete (T*)pData;} // Wrapper to release data by template virtual void deleteDataInstance(void* pData) const {delete (T*)pData;} // Wrapper to release data by template
// Disable TLS copy operations
TLSData(TLSData &) {};
TLSData& operator =(const TLSData &) {return *this;};
}; };
/** @brief Designed for command line parsing /** @brief Designed for command line parsing

View File

@ -1034,7 +1034,7 @@ class TlsStorage
public: public:
TlsStorage() TlsStorage()
{ {
tlsSlots = 0; tlsSlots.reserve(32);
threads.reserve(32); threads.reserve(32);
} }
~TlsStorage() ~TlsStorage()
@ -1077,15 +1077,27 @@ public:
size_t reserveSlot() size_t reserveSlot()
{ {
AutoLock guard(mtxGlobalAccess); AutoLock guard(mtxGlobalAccess);
tlsSlots++;
return (tlsSlots-1); // Find unused slots
for(size_t slot = 0; slot < tlsSlots.size(); slot++)
{
if(!tlsSlots[slot])
{
tlsSlots[slot] = 1;
return slot;
}
}
// Create new slot
tlsSlots.push_back(1);
return (tlsSlots.size()-1);
} }
// Release TLS storage index and pass assosiated data to caller // Release TLS storage index and pass assosiated data to caller
void releaseSlot(size_t slotIdx, std::vector<void*> &dataVec) void releaseSlot(size_t slotIdx, std::vector<void*> &dataVec)
{ {
AutoLock guard(mtxGlobalAccess); AutoLock guard(mtxGlobalAccess);
CV_Assert(tlsSlots > slotIdx); CV_Assert(tlsSlots.size() > slotIdx);
for(size_t i = 0; i < threads.size(); i++) for(size_t i = 0; i < threads.size(); i++)
{ {
@ -1096,15 +1108,14 @@ public:
threads[i]->slots[slotIdx] = 0; threads[i]->slots[slotIdx] = 0;
} }
} }
// If we removing last element, decriment slots size to save space
if(tlsSlots-1 == slotIdx) tlsSlots[slotIdx] = 0;
tlsSlots--;
} }
// Get data by TLS storage index // Get data by TLS storage index
void* getData(size_t slotIdx) const void* getData(size_t slotIdx) const
{ {
CV_Assert(tlsSlots > slotIdx); CV_Assert(tlsSlots.size() > slotIdx);
ThreadData* threadData = (ThreadData*)tls.GetData(); ThreadData* threadData = (ThreadData*)tls.GetData();
if(threadData && threadData->slots.size() > slotIdx) if(threadData && threadData->slots.size() > slotIdx)
@ -1113,10 +1124,24 @@ public:
return NULL; return NULL;
} }
// Gather data from threads by TLS storage index
void gather(size_t slotIdx, std::vector<void*> &dataVec)
{
AutoLock guard(mtxGlobalAccess);
CV_Assert(tlsSlots.size() > slotIdx);
for(size_t i = 0; i < threads.size(); i++)
{
std::vector<void*>& thread_slots = threads[i]->slots;
if (thread_slots.size() > slotIdx && thread_slots[slotIdx])
dataVec.push_back(thread_slots[slotIdx]);
}
}
// Set data to storage index // Set data to storage index
void setData(size_t slotIdx, void* pData) void setData(size_t slotIdx, void* pData)
{ {
CV_Assert(pData != NULL); CV_Assert(tlsSlots.size() > slotIdx && pData != NULL);
ThreadData* threadData = (ThreadData*)tls.GetData(); ThreadData* threadData = (ThreadData*)tls.GetData();
if(!threadData) if(!threadData)
@ -1131,7 +1156,11 @@ public:
} }
if(slotIdx >= threadData->slots.size()) if(slotIdx >= threadData->slots.size())
threadData->slots.resize(slotIdx+1); {
AutoLock guard(mtxGlobalAccess);
while(slotIdx >= threadData->slots.size())
threadData->slots.push_back(NULL);
}
threadData->slots[slotIdx] = pData; threadData->slots[slotIdx] = pData;
} }
@ -1139,7 +1168,7 @@ private:
TlsAbstraction tls; // TLS abstraction layer instance TlsAbstraction tls; // TLS abstraction layer instance
Mutex mtxGlobalAccess; // Shared objects operation guard Mutex mtxGlobalAccess; // Shared objects operation guard
size_t tlsSlots; // TLS storage counter std::vector<int> tlsSlots; // TLS keys state
std::vector<ThreadData*> threads; // Array for all allocated data. Thread data pointers are placed here to allow data cleanup std::vector<ThreadData*> threads; // Array for all allocated data. Thread data pointers are placed here to allow data cleanup
}; };
@ -1159,6 +1188,11 @@ TLSDataContainer::~TLSDataContainer()
CV_Assert(key_ == -1); // Key must be released in child object CV_Assert(key_ == -1); // Key must be released in child object
} }
void TLSDataContainer::gatherData(std::vector<void*> &data) const
{
getTlsStorage().gather(key_, data);
}
void TLSDataContainer::release() void TLSDataContainer::release()
{ {
std::vector<void*> data; std::vector<void*> data;