//===-- PerThreadTable.h -- PerThread Storage Structure ----*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Table indexed with one entry per thread. // //===----------------------------------------------------------------------===// #ifndef OFFLOAD_PERTHREADTABLE_H #define OFFLOAD_PERTHREADTABLE_H #include #include #include // Using an STL container (such as std::vector) indexed by thread ID has // too many race conditions issues so we store each thread entry into a // thread_local variable. // T is the container type used to store the objects, e.g., std::vector, // std::set, etc. by each thread. O is the type of the stored objects e.g., // omp_interop_val_t *, ... template struct PerThreadTable { using iterator = typename ContainerType::iterator; struct PerThreadData { size_t NElements = 0; std::unique_ptr ThEntry; }; std::mutex Mtx; std::list> ThreadDataList; // define default constructors, disable copy and move constructors PerThreadTable() = default; PerThreadTable(const PerThreadTable &) = delete; PerThreadTable(PerThreadTable &&) = delete; PerThreadTable &operator=(const PerThreadTable &) = delete; PerThreadTable &operator=(PerThreadTable &&) = delete; ~PerThreadTable() { std::lock_guard Lock(Mtx); ThreadDataList.clear(); } private: PerThreadData &getThreadData() { static thread_local std::shared_ptr ThData = nullptr; if (!ThData) { ThData = std::make_shared(); std::lock_guard Lock(Mtx); ThreadDataList.push_back(ThData); } return *ThData; } protected: ContainerType &getThreadEntry() { auto &ThData = getThreadData(); if (ThData.ThEntry) return *ThData.ThEntry; ThData.ThEntry = std::make_unique(); return *ThData.ThEntry; } size_t &getThreadNElements() { auto &ThData = getThreadData(); return ThData.NElements; } public: void add(ObjectType obj) { auto &Entry = getThreadEntry(); auto &NElements = getThreadNElements(); NElements++; Entry.add(obj); } iterator erase(iterator it) { auto &Entry = getThreadEntry(); auto &NElements = getThreadNElements(); NElements--; return Entry.erase(it); } size_t size() { return getThreadNElements(); } // Iterators to traverse objects owned by // the current thread iterator begin() { auto &Entry = getThreadEntry(); return Entry.begin(); } iterator end() { auto &Entry = getThreadEntry(); return Entry.end(); } template void clear(F f) { std::lock_guard Lock(Mtx); for (auto ThData : ThreadDataList) { if (!ThData->ThEntry || ThData->NElements == 0) continue; ThData->ThEntry->clear(f); ThData->NElements = 0; } ThreadDataList.clear(); } }; #endif