• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2020 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #pragma once
15 
16 #include "base/Lookup.h"
17 #include "base/EntityManager.h"
18 #include "base/Lock.h"
19 
20 #include <unordered_map>
21 
22 namespace android {
23 namespace base {
24 
25 template <size_t maxIndex,
26           class IndexType, // must be castable to uint64_t
27           class Data>
28 class HybridEntityManager {
29 public:
30     using EM = EntityManager<32, 16, 16, Data>;
31     using IterFunc = typename EM::IteratorFunc;
32     using ConstIterFunc = typename EM::ConstIteratorFunc;
33     using Handle = typename EM::EntityHandle;
34 
HybridEntityManager()35     HybridEntityManager() : mEntityManager(maxIndex + 1) { }
~HybridEntityManager()36     ~HybridEntityManager() { clear(); }
37 
add(const Data & data,size_t type)38     uint64_t add(const Data& data, size_t type) {
39         uint64_t nextIndex = 0;
40         {
41             SeqLock::ScopedWrite sw(&mEntityManagerLock);
42             nextIndex = (uint64_t)mEntityManager.nextFreeIndex();
43             if (nextIndex < maxIndex) {
44                 uint64_t resultHandle = mEntityManager.add(data, type);
45                 if (EM::getHandleIndex(resultHandle) != nextIndex) {
46                     fprintf(stderr, "%s: fatal: handle indices mismatch. wanted 0x%llx got 0x%llx\n", __func__,
47                             (unsigned long long)nextIndex,
48                             (unsigned long long)EM::getHandleIndex(resultHandle));
49                     abort();
50                 }
51                 return resultHandle;
52             }
53         }
54 
55         AutoLock lock(mMapLock);
56         if (mIndexForMap == 0) {
57             mIndexForMap = maxIndex;
58         }
59         nextIndex = mIndexForMap;
60         mMap[nextIndex] = data;
61         ++mIndexForMap;
62         return EM::makeHandle(nextIndex, 1, type);
63     }
64 
addFixed(IndexType index,const Data & data,size_t type)65     uint64_t addFixed(IndexType index, const Data& data, size_t type) {
66         uint64_t index_u64 = (uint64_t)EM::getHandleIndex(index);
67         if (index_u64 < maxIndex) {
68             SeqLock::ScopedWrite sw(&mEntityManagerLock);
69             return mEntityManager.addFixed(index, data, type);
70         } else {
71             AutoLock lock(mMapLock);
72             // Fixed allocations require us to update mIndexForMap to catch up with it.
73             // We assume that addFixed/add for the map case do not interleave badly
74             // (addFixed at i, add at i+1, addFixed at i+1)
75             mIndexForMap = index_u64;
76             mMap[index_u64] = data;
77             ++mIndexForMap;
78             return index;
79         }
80     }
81 
clear()82     void clear() {
83         {
84             SeqLock::ScopedWrite sw(&mEntityManagerLock);
85             mEntityManager.clear();
86         }
87         {
88             AutoLock lock(mMapLock);
89             mMap.clear();
90             mIndexForMap = 0;
91         }
92     }
93 
remove(IndexType index)94     void remove(IndexType index) {
95         uint64_t index_u64 = (uint64_t)EM::getHandleIndex(index);
96         if (index_u64 < maxIndex) {
97             SeqLock::ScopedWrite sw(&mEntityManagerLock);
98             mEntityManager.remove(index);
99         } else {
100             AutoLock lock(mMapLock);
101             mMap.erase(index_u64);
102         }
103     }
104 
get(IndexType index)105     Data* get(IndexType index) {
106         uint64_t index_u64 = (uint64_t)EM::getHandleIndex(index);
107         if (index_u64 < maxIndex) {
108             SeqLock::ScopedWrite sw(&mEntityManagerLock);
109             return mEntityManager.get(index);
110         } else {
111             AutoLock lock(mMapLock);
112             auto res = android::base::find(mMap, index_u64);
113             return res;
114         }
115     }
116 
get_const(IndexType index)117     const Data* get_const(IndexType index) const {
118         uint64_t index_u64 = (uint64_t)EM::getHandleIndex(index);
119         if (index_u64 < maxIndex) {
120             const Data* res;
121             AEMU_SEQLOCK_READ_WITH_RETRY(&mEntityManagerLock,
122                 res = mEntityManager.get_const(index));
123             return res;
124         } else {
125             AutoLock lock(mMapLock);
126             auto res = android::base::find(mMap, index_u64);
127             return res;
128         }
129     }
130 
getExceptZero(IndexType index)131     Data* getExceptZero(IndexType index) {
132         Data* res = get(index);
133         if (!res) return nullptr;
134         if (!(*res)) return nullptr;
135         return res;
136     }
137 
getExceptZero_const(IndexType index)138     const Data* getExceptZero_const(IndexType index) const {
139         const Data* res = get_const(index);
140         if (!res) return nullptr;
141         if (!(*res)) return nullptr;
142         return res;
143     }
144 
forEach(IterFunc func)145     void forEach(IterFunc func) {
146         {
147             SeqLock::ScopedWrite sw(&mEntityManagerLock);
148             mEntityManager.forEach(func);
149         }
150 
151         AutoLock lock(mMapLock);
152         for (auto it : mMap) {
153             auto handle = index2Handle(it.first);
154             func(true /* live */, handle, handle, it.second);
155         }
156     }
157 
forEachLive(IterFunc func)158     void forEachLive(IterFunc func) {
159         {
160             SeqLock::ScopedWrite sw(&mEntityManagerLock);
161             mEntityManager.forEachLiveComponent(func);
162         }
163 
164         AutoLock lock(mMapLock);
165         for (auto it : mMap) {
166             auto handle = index2Handle(it.first);
167             func(true /* live */, handle, handle, it.second);
168         }
169     }
170 
forEachLive_const(ConstIterFunc func)171     void forEachLive_const(ConstIterFunc func) const {
172         mEntityManager.forEachLiveEntry_const([this, func](bool live, Handle h, Data& d) {
173             AEMU_SEQLOCK_READ_WITH_RETRY(
174                 &mEntityManagerLock,
175                 func(live, h, d));
176         });
177 
178         AutoLock lock(mMapLock);
179         for (const auto it : mMap) {
180             auto handle = index2Handle(it.first);
181             func(true /* live */, handle, handle, it.second);
182         }
183     }
184 
185 private:
index2Handle(uint64_t index)186     static Handle index2Handle(uint64_t index) {
187         return EM::makeHandle((uint32_t)index, 1, 1);
188     }
189 
190     EM mEntityManager;
191     std::unordered_map<IndexType, Data> mMap;
192     uint64_t mIndexForMap = 0;
193     mutable SeqLock mEntityManagerLock;
194     mutable Lock mMapLock;
195 };
196 
197 } // namespace android
198 } // namespace base
199