| //===-- 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 <list> |
| #include <memory> |
| #include <mutex> |
| |
| // 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 <typename ContainerType, typename ObjectType> struct PerThreadTable { |
| using iterator = typename ContainerType::iterator; |
| |
| struct PerThreadData { |
| size_t NElements = 0; |
| std::unique_ptr<ContainerType> ThEntry; |
| }; |
| |
| std::mutex Mtx; |
| std::list<std::shared_ptr<PerThreadData>> 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<std::mutex> Lock(Mtx); |
| ThreadDataList.clear(); |
| } |
| |
| private: |
| PerThreadData &getThreadData() { |
| static thread_local std::shared_ptr<PerThreadData> ThData = nullptr; |
| if (!ThData) { |
| ThData = std::make_shared<PerThreadData>(); |
| std::lock_guard<std::mutex> 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<ContainerType>(); |
| 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 <class F> void clear(F f) { |
| std::lock_guard<std::mutex> Lock(Mtx); |
| for (auto ThData : ThreadDataList) { |
| if (!ThData->ThEntry || ThData->NElements == 0) |
| continue; |
| ThData->ThEntry->clear(f); |
| ThData->NElements = 0; |
| } |
| ThreadDataList.clear(); |
| } |
| }; |
| |
| #endif |