You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
255 lines
6.8 KiB
255 lines
6.8 KiB
// Copyright 2018 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
#include "base/SubAllocator.h"
|
|
|
|
#include "base/address_space.h"
|
|
#include "base/Stream.h"
|
|
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
namespace android {
|
|
namespace base {
|
|
|
|
class SubAllocator::Impl {
|
|
public:
|
|
Impl(
|
|
void* _buffer,
|
|
uint64_t _totalSize,
|
|
uint64_t _pageSize) :
|
|
buffer(_buffer),
|
|
totalSize(_totalSize),
|
|
pageSize(_pageSize),
|
|
startAddr((uintptr_t)buffer),
|
|
endAddr(startAddr + totalSize) {
|
|
|
|
address_space_allocator_init(
|
|
&addr_alloc,
|
|
totalSize,
|
|
32);
|
|
}
|
|
|
|
~Impl() {
|
|
address_space_allocator_destroy_nocleanup(&addr_alloc);
|
|
}
|
|
|
|
void clear() {
|
|
address_space_allocator_destroy_nocleanup(&addr_alloc);
|
|
address_space_allocator_init(
|
|
&addr_alloc,
|
|
totalSize,
|
|
32);
|
|
}
|
|
|
|
bool save(Stream* stream) {
|
|
address_space_allocator_iter_func_t allocatorSaver =
|
|
[](void* context, struct address_space_allocator* allocator) {
|
|
Stream* stream = reinterpret_cast<Stream*>(context);
|
|
stream->putBe32(allocator->size);
|
|
stream->putBe32(allocator->capacity);
|
|
stream->putBe64(allocator->total_bytes);
|
|
};
|
|
address_block_iter_func_t allocatorBlockSaver =
|
|
[](void* context, struct address_block* block) {
|
|
Stream* stream = reinterpret_cast<Stream*>(context);
|
|
stream->putBe64(block->offset);
|
|
stream->putBe64(block->size_available);
|
|
};
|
|
address_space_allocator_run(
|
|
&addr_alloc,
|
|
(void*)stream,
|
|
allocatorSaver,
|
|
allocatorBlockSaver);
|
|
|
|
stream->putBe64(pageSize);
|
|
stream->putBe64(totalSize);
|
|
stream->putBe32(allocCount);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool load(Stream* stream) {
|
|
clear();
|
|
address_space_allocator_iter_func_t allocatorLoader =
|
|
[](void* context, struct address_space_allocator* allocator) {
|
|
Stream* stream = reinterpret_cast<Stream*>(context);
|
|
allocator->size = stream->getBe32();
|
|
allocator->capacity = stream->getBe32();
|
|
allocator->total_bytes = stream->getBe64();
|
|
};
|
|
address_block_iter_func_t allocatorBlockLoader =
|
|
[](void* context, struct address_block* block) {
|
|
Stream* stream = reinterpret_cast<Stream*>(context);
|
|
block->offset = stream->getBe64();
|
|
block->size_available = stream->getBe64();
|
|
};
|
|
address_space_allocator_run(
|
|
&addr_alloc,
|
|
(void*)stream,
|
|
allocatorLoader,
|
|
allocatorBlockLoader);
|
|
|
|
pageSize = stream->getBe64();
|
|
totalSize = stream->getBe64();
|
|
allocCount = stream->getBe32();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool postLoad(void* postLoadBuffer) {
|
|
buffer = postLoadBuffer;
|
|
startAddr =
|
|
(uint64_t)(uintptr_t)postLoadBuffer;
|
|
return true;
|
|
}
|
|
|
|
void rangeCheck(const char* task, void* ptr) {
|
|
uint64_t addr = (uintptr_t)ptr;
|
|
if (addr < startAddr ||
|
|
addr > endAddr) {
|
|
std::stringstream ss;
|
|
ss << "SubAllocator " << task << ": ";
|
|
ss << "Out of range: " << std::hex << addr << " ";
|
|
ss << "Range: " <<
|
|
std::hex << startAddr << " " <<
|
|
std::hex << endAddr;
|
|
std::string msg = ss.str();
|
|
fprintf(stderr, "%s: range check failed: [%s]\n", __func__, msg.c_str());
|
|
}
|
|
}
|
|
|
|
uint64_t getOffset(void* checkedPtr) {
|
|
uint64_t addr = (uintptr_t)checkedPtr;
|
|
return addr - startAddr;
|
|
}
|
|
|
|
bool free(void* ptr) {
|
|
if (!ptr) return false;
|
|
|
|
rangeCheck("free", ptr);
|
|
if (EINVAL == address_space_allocator_deallocate(
|
|
&addr_alloc, getOffset(ptr))) {
|
|
return false;
|
|
}
|
|
|
|
--allocCount;
|
|
return true;
|
|
}
|
|
|
|
void freeAll() {
|
|
address_space_allocator_reset(&addr_alloc);
|
|
allocCount = 0;
|
|
}
|
|
|
|
void* alloc(size_t wantedSize) {
|
|
if (wantedSize == 0) return nullptr;
|
|
|
|
size_t toPageSize =
|
|
pageSize *
|
|
((wantedSize + pageSize - 1) / pageSize);
|
|
|
|
uint64_t offset =
|
|
address_space_allocator_allocate(
|
|
&addr_alloc, toPageSize);
|
|
|
|
if (offset == ANDROID_EMU_ADDRESS_SPACE_BAD_OFFSET) {
|
|
return nullptr;
|
|
}
|
|
|
|
++allocCount;
|
|
return (void*)(uintptr_t)(startAddr + offset);
|
|
}
|
|
|
|
void* allocFixed(size_t wantedSize, uint64_t offset) {
|
|
|
|
if (wantedSize == 0) return nullptr;
|
|
|
|
size_t toPageSize =
|
|
pageSize *
|
|
((wantedSize + pageSize - 1) / pageSize);
|
|
|
|
if (address_space_allocator_allocate_fixed(
|
|
&addr_alloc, toPageSize, offset)) {
|
|
return nullptr;
|
|
}
|
|
|
|
++allocCount;
|
|
return (void*)(uintptr_t)(startAddr + offset);
|
|
}
|
|
|
|
bool empty() const {
|
|
return allocCount == 0;
|
|
}
|
|
|
|
void* buffer;
|
|
uint64_t totalSize;
|
|
uint64_t pageSize;
|
|
uint64_t startAddr;
|
|
uint64_t endAddr;
|
|
struct address_space_allocator addr_alloc;
|
|
uint32_t allocCount = 0;
|
|
};
|
|
|
|
SubAllocator::SubAllocator(
|
|
void* buffer,
|
|
uint64_t totalSize,
|
|
uint64_t pageSize) :
|
|
mImpl(
|
|
new SubAllocator::Impl(buffer, totalSize, pageSize)) { }
|
|
|
|
SubAllocator::~SubAllocator() {
|
|
delete mImpl;
|
|
}
|
|
|
|
// Snapshotting
|
|
bool SubAllocator::save(Stream* stream) {
|
|
return mImpl->save(stream);
|
|
}
|
|
|
|
bool SubAllocator::load(Stream* stream) {
|
|
return mImpl->load(stream);
|
|
}
|
|
|
|
bool SubAllocator::postLoad(void* postLoadBuffer) {
|
|
return mImpl->postLoad(postLoadBuffer);
|
|
}
|
|
|
|
void* SubAllocator::alloc(size_t wantedSize) {
|
|
return mImpl->alloc(wantedSize);
|
|
}
|
|
|
|
void* SubAllocator::allocFixed(size_t wantedSize, uint64_t offset) {
|
|
return mImpl->allocFixed(wantedSize, offset);
|
|
}
|
|
|
|
bool SubAllocator::free(void* ptr) {
|
|
return mImpl->free(ptr);
|
|
}
|
|
|
|
void SubAllocator::freeAll() {
|
|
mImpl->freeAll();
|
|
}
|
|
|
|
uint64_t SubAllocator::getOffset(void* ptr) {
|
|
return mImpl->getOffset(ptr);
|
|
}
|
|
|
|
bool SubAllocator::empty() const {
|
|
return mImpl->empty();
|
|
}
|
|
|
|
} // namespace base
|
|
} // namespace android
|