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 "aemu/base/containers/Lookup.h" 17 #include "aemu/base/containers/EntityManager.h" 18 #include "aemu/base/synchronization/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 auto emplaced = mMap.emplace(nextIndex, data); 61 if (!emplaced.second) { 62 fprintf(stderr, "%s: fatal: trying to insert duplicated entry 0x%llx\n", __func__, 63 (unsigned long long)nextIndex); 64 abort(); 65 } 66 ++mIndexForMap; 67 return EM::makeHandle(nextIndex, 1, type); 68 } 69 addFixed(IndexType index,const Data & data,size_t type)70 uint64_t addFixed(IndexType index, const Data& data, size_t type) { 71 uint64_t index_u64 = (uint64_t)EM::getHandleIndex(index); 72 if (index_u64 < maxIndex) { 73 SeqLock::ScopedWrite sw(&mEntityManagerLock); 74 return mEntityManager.addFixed(index, data, type); 75 } else { 76 AutoLock lock(mMapLock); 77 // Fixed allocations require us to update mIndexForMap to catch up with it. 78 mIndexForMap = std::max(index_u64 + 1, mIndexForMap); 79 auto emplaced = mMap.emplace(index_u64, data); 80 if (!emplaced.second) { 81 fprintf(stderr, "%s: fatal: trying to insert duplicated entry 0x%llx\n", __func__, 82 (unsigned long long)index_u64); 83 abort(); 84 } 85 return index; 86 } 87 } 88 clear()89 void clear() { 90 { 91 SeqLock::ScopedWrite sw(&mEntityManagerLock); 92 mEntityManager.clear(); 93 } 94 { 95 AutoLock lock(mMapLock); 96 mMap.clear(); 97 mIndexForMap = 0; 98 } 99 } 100 remove(IndexType index)101 void remove(IndexType index) { 102 uint64_t index_u64 = (uint64_t)EM::getHandleIndex(index); 103 if (index_u64 < maxIndex) { 104 SeqLock::ScopedWrite sw(&mEntityManagerLock); 105 mEntityManager.remove(index); 106 } else { 107 AutoLock lock(mMapLock); 108 mMap.erase(index_u64); 109 } 110 } 111 get(IndexType index)112 Data* get(IndexType index) { 113 uint64_t index_u64 = (uint64_t)EM::getHandleIndex(index); 114 if (index_u64 < maxIndex) { 115 SeqLock::ScopedWrite sw(&mEntityManagerLock); 116 return mEntityManager.get(index); 117 } else { 118 AutoLock lock(mMapLock); 119 auto res = android::base::find(mMap, index_u64); 120 return res; 121 } 122 } 123 get_const(IndexType index)124 const Data* get_const(IndexType index) const { 125 uint64_t index_u64 = (uint64_t)EM::getHandleIndex(index); 126 if (index_u64 < maxIndex) { 127 const Data* res; 128 AEMU_SEQLOCK_READ_WITH_RETRY(&mEntityManagerLock, 129 res = mEntityManager.get_const(index)); 130 return res; 131 } else { 132 AutoLock lock(mMapLock); 133 auto res = android::base::find(mMap, index_u64); 134 return res; 135 } 136 } 137 getExceptZero(IndexType index)138 Data* getExceptZero(IndexType index) { 139 Data* res = get(index); 140 if (!res) return nullptr; 141 if (!(*res)) return nullptr; 142 return res; 143 } 144 getExceptZero_const(IndexType index)145 const Data* getExceptZero_const(IndexType index) const { 146 const Data* res = get_const(index); 147 if (!res) return nullptr; 148 if (!(*res)) return nullptr; 149 return res; 150 } 151 forEach(IterFunc func)152 void forEach(IterFunc func) { 153 { 154 SeqLock::ScopedWrite sw(&mEntityManagerLock); 155 mEntityManager.forEach(func); 156 } 157 158 AutoLock lock(mMapLock); 159 for (auto it : mMap) { 160 auto handle = index2Handle(it.first); 161 func(true /* live */, handle, handle, it.second); 162 } 163 } 164 forEachLive(IterFunc func)165 void forEachLive(IterFunc func) { 166 { 167 SeqLock::ScopedWrite sw(&mEntityManagerLock); 168 mEntityManager.forEachLiveComponent(func); 169 } 170 171 AutoLock lock(mMapLock); 172 for (auto it : mMap) { 173 auto handle = index2Handle(it.first); 174 func(true /* live */, handle, handle, it.second); 175 } 176 } 177 forEachLive_const(ConstIterFunc func)178 void forEachLive_const(ConstIterFunc func) const { 179 mEntityManager.forEachLiveEntry_const([this, func](bool live, Handle h, Data& d) { 180 AEMU_SEQLOCK_READ_WITH_RETRY( 181 &mEntityManagerLock, 182 func(live, h, d)); 183 }); 184 185 AutoLock lock(mMapLock); 186 for (const auto it : mMap) { 187 auto handle = index2Handle(it.first); 188 func(true /* live */, handle, handle, it.second); 189 } 190 } 191 192 private: index2Handle(uint64_t index)193 static Handle index2Handle(uint64_t index) { 194 return EM::makeHandle((uint32_t)index, 1, 1); 195 } 196 197 EM mEntityManager; 198 std::unordered_map<IndexType, Data> mMap; 199 uint64_t mIndexForMap = 0; 200 mutable SeqLock mEntityManagerLock; 201 mutable Lock mMapLock; 202 }; 203 204 } // namespace android 205 } // namespace base 206