• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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 #include "aemu/base/SubAllocator.h"
15 
16 #include "aemu/base/address_space.h"
17 #include "aemu/base/files/Stream.h"
18 
19 #include <iomanip>
20 #include <sstream>
21 #include <string>
22 
23 namespace android {
24 namespace base {
25 
26 class SubAllocator::Impl {
27 public:
Impl(void * _buffer,uint64_t _totalSize,uint64_t _pageSize)28     Impl(
29         void* _buffer,
30         uint64_t _totalSize,
31         uint64_t _pageSize) :
32         buffer(_buffer),
33         totalSize(_totalSize),
34         pageSize(_pageSize),
35         startAddr((uintptr_t)buffer),
36         endAddr(startAddr + totalSize) {
37 
38         address_space_allocator_init(
39             &addr_alloc,
40             totalSize,
41             32);
42     }
43 
~Impl()44     ~Impl() {
45         address_space_allocator_destroy_nocleanup(&addr_alloc);
46     }
47 
clear()48     void clear() {
49         address_space_allocator_destroy_nocleanup(&addr_alloc);
50         address_space_allocator_init(
51             &addr_alloc,
52             totalSize,
53             32);
54     }
55 
save(Stream * stream)56     bool save(Stream* stream) {
57         address_space_allocator_iter_func_t allocatorSaver =
58             [](void* context, struct address_space_allocator* allocator) {
59                 Stream* stream = reinterpret_cast<Stream*>(context);
60                 stream->putBe32(allocator->size);
61                 stream->putBe32(allocator->capacity);
62                 stream->putBe64(allocator->total_bytes);
63             };
64         address_block_iter_func_t allocatorBlockSaver =
65             [](void* context, struct address_block* block) {
66                 Stream* stream = reinterpret_cast<Stream*>(context);
67                 stream->putBe64(block->offset);
68                 stream->putBe64(block->size_available);
69             };
70         address_space_allocator_run(
71             &addr_alloc,
72             (void*)stream,
73             allocatorSaver,
74             allocatorBlockSaver);
75 
76         stream->putBe64(pageSize);
77         stream->putBe64(totalSize);
78         stream->putBe32(allocCount);
79 
80         return true;
81     }
82 
load(Stream * stream)83     bool load(Stream* stream) {
84         clear();
85         address_space_allocator_iter_func_t allocatorLoader =
86             [](void* context, struct address_space_allocator* allocator) {
87                 Stream* stream = reinterpret_cast<Stream*>(context);
88                 allocator->size = stream->getBe32();
89                 allocator->capacity = stream->getBe32();
90                 allocator->total_bytes = stream->getBe64();
91             };
92         address_block_iter_func_t allocatorBlockLoader =
93             [](void* context, struct address_block* block) {
94                 Stream* stream = reinterpret_cast<Stream*>(context);
95                 block->offset = stream->getBe64();
96                 block->size_available = stream->getBe64();
97             };
98         address_space_allocator_run(
99             &addr_alloc,
100             (void*)stream,
101             allocatorLoader,
102             allocatorBlockLoader);
103 
104         pageSize = stream->getBe64();
105         totalSize = stream->getBe64();
106         allocCount = stream->getBe32();
107 
108         return true;
109     }
110 
postLoad(void * postLoadBuffer)111     bool postLoad(void* postLoadBuffer) {
112         buffer = postLoadBuffer;
113         startAddr =
114             (uint64_t)(uintptr_t)postLoadBuffer;
115         return true;
116     }
117 
rangeCheck(const char * task,void * ptr)118     void rangeCheck(const char* task, void* ptr) {
119         uint64_t addr = (uintptr_t)ptr;
120         if (addr < startAddr ||
121             addr > endAddr) {
122             std::stringstream ss;
123             ss << "SubAllocator " << task << ": ";
124             ss << "Out of range: " << std::hex << addr << " ";
125             ss << "Range: " <<
126                 std::hex << startAddr << " " <<
127                 std::hex << endAddr;
128             std::string msg = ss.str();
129             fprintf(stderr, "%s: range check failed: [%s]\n", __func__, msg.c_str());
130         }
131     }
132 
getOffset(void * checkedPtr)133     uint64_t getOffset(void* checkedPtr) {
134         uint64_t addr = (uintptr_t)checkedPtr;
135         return addr - startAddr;
136     }
137 
free(void * ptr)138     bool free(void* ptr) {
139         if (!ptr) return false;
140 
141         rangeCheck("free", ptr);
142         if (EINVAL == address_space_allocator_deallocate(
143             &addr_alloc, getOffset(ptr))) {
144             return false;
145         }
146 
147         --allocCount;
148         return true;
149     }
150 
freeAll()151     void freeAll() {
152         address_space_allocator_reset(&addr_alloc);
153         allocCount = 0;
154     }
155 
alloc(size_t wantedSize)156     void* alloc(size_t wantedSize) {
157         if (wantedSize == 0) return nullptr;
158 
159         size_t toPageSize =
160             pageSize *
161             ((wantedSize + pageSize - 1) / pageSize);
162 
163         uint64_t offset =
164             address_space_allocator_allocate(
165                 &addr_alloc, toPageSize);
166 
167         if (offset == ANDROID_EMU_ADDRESS_SPACE_BAD_OFFSET) {
168             return nullptr;
169         }
170 
171         ++allocCount;
172         return (void*)(uintptr_t)(startAddr + offset);
173     }
174 
allocFixed(size_t wantedSize,uint64_t offset)175     void* allocFixed(size_t wantedSize, uint64_t offset) {
176 
177         if (wantedSize == 0) return nullptr;
178 
179         size_t toPageSize =
180             pageSize *
181             ((wantedSize + pageSize - 1) / pageSize);
182 
183         if (address_space_allocator_allocate_fixed(
184                 &addr_alloc, toPageSize, offset)) {
185             return nullptr;
186         }
187 
188         ++allocCount;
189         return (void*)(uintptr_t)(startAddr + offset);
190     }
191 
empty() const192     bool empty() const {
193         return allocCount == 0;
194     }
195 
196     void* buffer;
197     uint64_t totalSize;
198     uint64_t pageSize;
199     uint64_t startAddr;
200     uint64_t endAddr;
201     struct address_space_allocator addr_alloc;
202     uint32_t allocCount = 0;
203 };
204 
SubAllocator(void * buffer,uint64_t totalSize,uint64_t pageSize)205 SubAllocator::SubAllocator(
206     void* buffer,
207     uint64_t totalSize,
208     uint64_t pageSize) :
209     mImpl(
210         new SubAllocator::Impl(buffer, totalSize, pageSize)) { }
211 
~SubAllocator()212 SubAllocator::~SubAllocator() {
213     delete mImpl;
214 }
215 
216 // Snapshotting
save(Stream * stream)217 bool SubAllocator::save(Stream* stream) {
218     return mImpl->save(stream);
219 }
220 
load(Stream * stream)221 bool SubAllocator::load(Stream* stream) {
222     return mImpl->load(stream);
223 }
224 
postLoad(void * postLoadBuffer)225 bool SubAllocator::postLoad(void* postLoadBuffer) {
226     return mImpl->postLoad(postLoadBuffer);
227 }
228 
alloc(size_t wantedSize)229 void* SubAllocator::alloc(size_t wantedSize) {
230     return mImpl->alloc(wantedSize);
231 }
232 
allocFixed(size_t wantedSize,uint64_t offset)233 void* SubAllocator::allocFixed(size_t wantedSize, uint64_t offset) {
234     return mImpl->allocFixed(wantedSize, offset);
235 }
236 
free(void * ptr)237 bool SubAllocator::free(void* ptr) {
238     return mImpl->free(ptr);
239 }
240 
freeAll()241 void SubAllocator::freeAll() {
242     mImpl->freeAll();
243 }
244 
getOffset(void * ptr)245 uint64_t SubAllocator::getOffset(void* ptr) {
246     return mImpl->getOffset(ptr);
247 }
248 
empty() const249 bool SubAllocator::empty() const {
250     return mImpl->empty();
251 }
252 
253 } // namespace base
254 } // namespace android
255