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 "android/base/SubAllocator.h"
15
16 #include "android/base/address_space.h"
17
18 #include <log/log.h>
19
20 #include <iomanip>
21 #include <sstream>
22 #include <string>
23
24 namespace android {
25 namespace base {
26
27 class SubAllocator::Impl {
28 public:
Impl(void * _buffer,uint64_t _totalSize,uint64_t _pageSize)29 Impl(
30 void* _buffer,
31 uint64_t _totalSize,
32 uint64_t _pageSize) :
33 buffer(_buffer),
34 totalSize(_totalSize),
35 pageSize(_pageSize),
36 startAddr((uintptr_t)buffer),
37 endAddr(startAddr + totalSize) {
38
39 address_space_allocator_init(
40 &addr_alloc,
41 totalSize,
42 32);
43 }
44
~Impl()45 ~Impl() {
46 address_space_allocator_destroy(&addr_alloc);
47 }
48
rangeCheck(const char * task,void * ptr)49 void rangeCheck(const char* task, void* ptr) {
50 uint64_t addr = (uintptr_t)ptr;
51 if (addr < startAddr ||
52 addr > endAddr) {
53 std::stringstream ss;
54 ss << "SubAllocator " << task << ": ";
55 ss << "Out of range: " << std::hex << addr << " ";
56 ss << "Range: " <<
57 std::hex << startAddr << " " <<
58 std::hex << endAddr;
59 std::string msg = ss.str();
60 ALOGE("%s", msg.c_str());
61 abort();
62 }
63 }
64
getOffset(void * checkedPtr)65 uint64_t getOffset(void* checkedPtr) {
66 uint64_t addr = (uintptr_t)checkedPtr;
67 return addr - startAddr;
68 }
69
free(void * ptr)70 void free(void* ptr) {
71 if (!ptr) return;
72
73 rangeCheck("free", ptr);
74 address_space_allocator_deallocate(
75 &addr_alloc, getOffset(ptr));
76 }
77
freeAll()78 void freeAll() {
79 address_space_allocator_reset(&addr_alloc);
80 }
81
alloc(size_t wantedSize)82 void* alloc(size_t wantedSize) {
83 if (wantedSize == 0) return nullptr;
84
85 uint64_t wantedSize64 =
86 (uint64_t)wantedSize;
87
88 size_t toPageSize =
89 pageSize *
90 ((wantedSize + pageSize - 1) / pageSize);
91
92 uint64_t offset =
93 address_space_allocator_allocate(
94 &addr_alloc, toPageSize);
95
96 if (offset == ANDROID_EMU_ADDRESS_SPACE_BAD_OFFSET) {
97 return nullptr;
98 }
99
100 return (void*)(uintptr_t)(startAddr + offset);
101 }
102
103 void* buffer;
104 uint64_t totalSize;
105 uint64_t pageSize;
106 uint64_t startAddr;
107 uint64_t endAddr;
108 struct address_space_allocator addr_alloc;
109 };
110
SubAllocator(void * buffer,uint64_t totalSize,uint64_t pageSize)111 SubAllocator::SubAllocator(
112 void* buffer,
113 uint64_t totalSize,
114 uint64_t pageSize) :
115 mImpl(
116 new SubAllocator::Impl(buffer, totalSize, pageSize)) { }
117
~SubAllocator()118 SubAllocator::~SubAllocator() {
119 delete mImpl;
120 }
121
alloc(size_t wantedSize)122 void* SubAllocator::alloc(size_t wantedSize) {
123 return mImpl->alloc(wantedSize);
124 }
125
free(void * ptr)126 void SubAllocator::free(void* ptr) {
127 mImpl->free(ptr);
128 }
129
freeAll()130 void SubAllocator::freeAll() {
131 mImpl->freeAll();
132 }
133
getOffset(void * ptr)134 uint64_t SubAllocator::getOffset(void* ptr) {
135 return mImpl->getOffset(ptr);
136 }
137
138 } // namespace base
139 } // namespace android
140