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