• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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