#include <opencv2/core/utils/tls.hpp>
#include <opencv2/core/utils/instrumentation.hpp>
+#include <opencv2/core/utils/filesystem.private.hpp>
+
+ #ifndef OPENCV_WITH_THREAD_SANITIZER
+ #if defined(__clang__) && defined(__has_feature)
+ #if __has_feature(thread_sanitizer)
+ #define OPENCV_WITH_THREAD_SANITIZER 1
+ #include <atomic> // assume C++11
+ #endif
+ #endif
+ #endif
+ #ifndef OPENCV_WITH_THREAD_SANITIZER
+ #define OPENCV_WITH_THREAD_SANITIZER 0
+ #endif
+
namespace cv {
static void _initSystem()
#endif
};
- template<> bool DisposedSingletonMark<TlsAbstraction>::mark = false;
-
- static TlsAbstraction& getTlsAbstraction_()
+ class TlsAbstractionReleaseGuard
{
- static TlsAbstraction g_tls; // disposed in atexit() handlers (required for unregistering our callbacks)
- return g_tls;
- }
+ TlsAbstraction& tls_;
+ public:
+ TlsAbstractionReleaseGuard(TlsAbstraction& tls) : tls_(tls)
+ {
+ /* nothing */
+ }
+ ~TlsAbstractionReleaseGuard()
+ {
+ tls_.releaseSystemResources();
+ }
+ };
+
+ // TODO use reference
static TlsAbstraction* getTlsAbstraction()
{
- static TlsAbstraction* instance = &getTlsAbstraction_();
- return DisposedSingletonMark<TlsAbstraction>::isDisposed() ? NULL : instance;
-#ifdef CV_CXX11
+ static TlsAbstraction *g_tls = new TlsAbstraction(); // memory leak is intended here to avoid disposing of TLS container
+ static TlsAbstractionReleaseGuard g_tlsReleaseGuard(*g_tls);
-#else
- static TlsAbstraction* volatile g_tls = NULL;
- if (g_tls == NULL)
- {
- cv::AutoLock lock(cv::getInitializationMutex());
- if (g_tls == NULL)
- {
- g_tls = new TlsAbstraction();
- static TlsAbstractionReleaseGuard g_tlsReleaseGuard(*g_tls);
- }
- }
-#endif
+ return g_tls;
}
#if defined __GNUC__
__attribute__((unused))
#endif
- = getTlsAbstraction();
+ = &getTlsStorage();
+
+#else // OPENCV_DISABLE_THREAD_SUPPORT
+
+// no threading (OPENCV_DISABLE_THREAD_SUPPORT=ON)
+class TlsStorage
+{
+public:
+ TlsStorage()
+ {
+ slots.reserve(32);
+ }
+ ~TlsStorage()
+ {
+ for (size_t slotIdx = 0; slotIdx < slots.size(); slotIdx++)
+ {
+ SlotInfo& s = slots[slotIdx];
+ TLSDataContainer* container = s.container;
+ if (container && s.data)
+ {
+ container->deleteDataInstance(s.data); // Can't use from SlotInfo destructor
+ s.data = nullptr;
+ }
+ }
+ }
+
+ // Reserve TLS storage index
+ size_t reserveSlot(TLSDataContainer* container)
+ {
+ size_t slotsSize = slots.size();
+ for (size_t slot = 0; slot < slotsSize; slot++)
+ {
+ SlotInfo& s = slots[slot];
+ if (s.container == NULL)
+ {
+ CV_Assert(!s.data);
+ s.container = container;
+ return slot;
+ }
+ }
+
+ // create new slot
+ slots.push_back(SlotInfo(container));
+ return slotsSize;
+ }
+
+ // Release TLS storage index and pass associated data to caller
+ void releaseSlot(size_t slotIdx, std::vector<void*> &dataVec, bool keepSlot = false)
+ {
+ CV_Assert(slotIdx < slots.size());
+ SlotInfo& s = slots[slotIdx];
+ void* data = s.data;
+ if (data)
+ {
+ dataVec.push_back(data);
+ s.data = nullptr;
+ }
+ if (!keepSlot)
+ {
+ s.container = NULL; // mark slot as free (see reserveSlot() implementation)
+ }
+ }
+
+ // Get data by TLS storage index
+ void* getData(size_t slotIdx) const
+ {
+ CV_Assert(slotIdx < slots.size());
+ const SlotInfo& s = slots[slotIdx];
+ return s.data;
+ }
+
+ // Gather data from threads by TLS storage index
+ void gather(size_t slotIdx, std::vector<void*> &dataVec)
+ {
+ CV_Assert(slotIdx < slots.size());
+ SlotInfo& s = slots[slotIdx];
+ void* data = s.data;
+ if (data)
+ dataVec.push_back(data);
+ return;
+ }
+
+ // Set data to storage index
+ void setData(size_t slotIdx, void* pData)
+ {
+ CV_Assert(slotIdx < slots.size());
+ SlotInfo& s = slots[slotIdx];
+ s.data = pData;
+ }
+
+private:
+ struct SlotInfo
+ {
+ SlotInfo(TLSDataContainer* _container) : container(_container), data(nullptr) {}
+ TLSDataContainer* container; // attached container (to dispose data)
+ void* data;
+ };
+ std::vector<struct SlotInfo> slots;
+};
+
+static TlsStorage& getTlsStorage()
+{
+ static TlsStorage g_storage; // no threading
+ return g_storage;
+}
+
+#endif // OPENCV_DISABLE_THREAD_SUPPORT
+
} // namespace details
using namespace details;