1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #pragma once 17 18 #include "base/Lookup.h" 19 #include "base/Stream.h" 20 #include "base/StreamSerializing.h" 21 #include "base/Lock.h" 22 #include "base/Compiler.h" 23 24 #include <algorithm> 25 #include <cstdint> 26 #include <unordered_map> 27 28 // The purpose of StalePtrRegistry is to track integers corresponding to 29 // host-side pointers that may be invalidated after snapshots. 30 template <class T> 31 class StalePtrRegistry { 32 public: 33 StalePtrRegistry() = default; 34 addPtr(T * ptr)35 void addPtr(T* ptr) { 36 android::base::AutoWriteLock lock(mLock); 37 mPtrs[asHandle(ptr)] = { ptr, Staleness::Live }; 38 } 39 removePtr(T * ptr)40 void removePtr(T* ptr) { 41 android::base::AutoWriteLock lock(mLock); 42 uint64_t handle = asHandle(ptr); 43 mPtrs.erase(handle); 44 } 45 remapStalePtr(uint64_t handle,T * newptr)46 void remapStalePtr(uint64_t handle, T* newptr) { 47 android::base::AutoWriteLock lock(mLock); 48 mPtrs[handle] = { newptr, Staleness::PrevSnapshot }; 49 } 50 51 T* getPtr(uint64_t handle, T* defaultPtr = nullptr, 52 bool removeFromStaleOnGet = false) { 53 android::base::AutoReadLock lock(mLock); 54 55 // return |defaultPtr| if not found. 56 T* res = defaultPtr; 57 58 Entry* it = nullptr; 59 60 if ((it = android::base::find(mPtrs, handle))) 61 res = it->ptr; 62 63 if (removeFromStaleOnGet && 64 it && it->staleness == Staleness::PrevSnapshot) { 65 lock.unlockRead(); 66 android::base::AutoWriteLock wrlock(mLock); 67 mPtrs.erase(handle); 68 } 69 70 return res; 71 } 72 makeCurrentPtrsStale()73 void makeCurrentPtrsStale() { 74 android::base::AutoWriteLock lock(mLock); 75 for (auto& it : mPtrs) { 76 it.second.staleness = 77 Staleness::PrevSnapshot; 78 } 79 } 80 numCurrEntries()81 size_t numCurrEntries() const { 82 return countWithStaleness(Staleness::Live); 83 } 84 numStaleEntries()85 size_t numStaleEntries() const { 86 return countWithStaleness(Staleness::PrevSnapshot); 87 } 88 onSave(android::base::Stream * stream)89 void onSave(android::base::Stream* stream) { 90 android::base::AutoReadLock lock(mLock); 91 saveCollection( 92 stream, mPtrs, 93 [](android::base::Stream* stream, 94 const std::pair<uint64_t, Entry>& entry) { 95 stream->putBe64(entry.first); 96 }); 97 } 98 onLoad(android::base::Stream * stream)99 void onLoad(android::base::Stream* stream) { 100 android::base::AutoWriteLock lock(mLock); 101 loadCollection( 102 stream, &mPtrs, 103 [](android::base::Stream* stream) { 104 uint64_t handle = stream->getBe64(); 105 return std::make_pair( 106 handle, 107 (Entry){ nullptr, Staleness::PrevSnapshot }); 108 }); 109 } 110 private: asHandle(const T * ptr)111 static uint64_t asHandle(const T* ptr) { 112 return (uint64_t)(uintptr_t)ptr; 113 } 114 asPtr(uint64_t handle)115 static T* asPtr(uint64_t handle) { 116 return (T*)(uintptr_t)handle; 117 } 118 119 enum class Staleness { 120 Live, 121 PrevSnapshot, 122 }; 123 struct Entry { 124 T* ptr; 125 Staleness staleness; 126 }; 127 128 using PtrMap = std::unordered_map<uint64_t, Entry>; 129 countWithStaleness(Staleness check)130 size_t countWithStaleness(Staleness check) const { 131 android::base::AutoReadLock lock(mLock); 132 return std::count_if(mPtrs.begin(), mPtrs.end(), 133 [check](const typename PtrMap::value_type& entry) { 134 return entry.second.staleness == check; 135 }); 136 } 137 138 mutable android::base::ReadWriteLock mLock; 139 PtrMap mPtrs; 140 141 DISALLOW_COPY_AND_ASSIGN(StalePtrRegistry); 142 }; 143