| // Copyright 2016 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <zircon/listnode.h> // for containerof |
| #include <region-alloc/region-alloc.h> |
| |
| extern "C" { |
| |
| zx_status_t ralloc_create_pool(size_t max_memory, ralloc_pool_t** out_pool) { |
| if (out_pool == nullptr) |
| return ZX_ERR_INVALID_ARGS; |
| |
| auto pool = RegionAllocator::RegionPool::Create(max_memory); |
| if (pool == nullptr) |
| return ZX_ERR_NO_MEMORY; |
| |
| // Everything looks good. Deliberately leak our reference out into the cold |
| // cruel world of C. I sure hope that it comes back some day... |
| *out_pool = reinterpret_cast<ralloc_pool_t*>(fbl::ExportToRawPtr(&pool)); |
| |
| return ZX_OK; |
| } |
| |
| void ralloc_release_pool(ralloc_pool_t* pool) { |
| ZX_DEBUG_ASSERT(pool != nullptr); |
| |
| // Reclaim our reference back from the land of C by turning the pointer |
| // back into a RefPtr, then deliberately let it go out of scope, dropping |
| // its reference and destructing the RegionPool if need be. |
| auto release_me = |
| fbl::ImportFromRawPtr(reinterpret_cast<RegionAllocator::RegionPool*>(pool)); |
| } |
| |
| zx_status_t ralloc_create_allocator(ralloc_allocator_t** out_allocator) { |
| if (!out_allocator) |
| return ZX_ERR_INVALID_ARGS; |
| |
| void* mem = ::malloc(sizeof(RegionAllocator)); |
| if (!mem) |
| return ZX_ERR_NO_MEMORY; |
| |
| *out_allocator = reinterpret_cast<ralloc_allocator_t*>(new (mem) RegionAllocator()); |
| return ZX_OK; |
| } |
| |
| zx_status_t ralloc_set_region_pool(ralloc_allocator_t* allocator, ralloc_pool* pool) { |
| if (!allocator || !pool) |
| return ZX_ERR_INVALID_ARGS; |
| |
| RegionAllocator& alloc = *(reinterpret_cast<RegionAllocator*>(allocator)); |
| |
| // Turn our C-style pointer back into a RefPtr<> without adding a reference, |
| // then use it to call the RegionAllocator::SetRegionPool method. Finally, |
| // deliberately leak the reference again so we are not accidentally removing |
| // the unmanaged reference held by our C user. |
| auto pool_ref = |
| fbl::ImportFromRawPtr(reinterpret_cast<RegionAllocator::RegionPool*>(pool)); |
| zx_status_t ret = alloc.SetRegionPool(pool_ref); |
| __UNUSED auto leak = fbl::ExportToRawPtr(&pool_ref); |
| |
| return ret; |
| } |
| |
| void ralloc_reset_allocator(ralloc_allocator_t* allocator) { |
| ZX_DEBUG_ASSERT(allocator); |
| reinterpret_cast<RegionAllocator*>(allocator)->Reset(); |
| } |
| |
| void ralloc_destroy_allocator(ralloc_allocator_t* allocator) { |
| ZX_DEBUG_ASSERT(allocator); |
| |
| RegionAllocator* alloc = reinterpret_cast<RegionAllocator*>(allocator); |
| alloc->~RegionAllocator(); |
| ::free(alloc); |
| } |
| |
| zx_status_t ralloc_add_region(ralloc_allocator_t* allocator, const ralloc_region_t* region, |
| bool allow_overlap) { |
| if (!allocator || !region) |
| return ZX_ERR_INVALID_ARGS; |
| |
| return reinterpret_cast<RegionAllocator*>(allocator)->AddRegion(*region, allow_overlap); |
| } |
| |
| zx_status_t ralloc_sub_region(ralloc_allocator_t* allocator, const ralloc_region_t* region, |
| bool allow_incomplete) { |
| if (!allocator || !region) |
| return ZX_ERR_INVALID_ARGS; |
| |
| return reinterpret_cast<RegionAllocator*>(allocator)->SubtractRegion(*region, allow_incomplete); |
| } |
| |
| zx_status_t ralloc_get_sized_region_ex(ralloc_allocator_t* allocator, uint64_t size, |
| uint64_t alignment, const ralloc_region_t** out_region) { |
| if (!allocator || !out_region) |
| return ZX_ERR_INVALID_ARGS; |
| |
| RegionAllocator::Region::UPtr managed_region; |
| RegionAllocator& alloc = *(reinterpret_cast<RegionAllocator*>(allocator)); |
| zx_status_t result = alloc.GetRegion(size, alignment, managed_region); |
| |
| if (result == ZX_OK) { |
| // Everything looks good. Detach the managed_region our unique_ptr<> |
| // and send the unmanaged pointer to the inner ralloc_region_t back |
| // to the caller. |
| ZX_DEBUG_ASSERT(managed_region != nullptr); |
| const RegionAllocator::Region* raw_region = managed_region.release(); |
| *out_region = static_cast<const ralloc_region_t*>(raw_region); |
| } else { |
| ZX_DEBUG_ASSERT(managed_region == nullptr); |
| *out_region = nullptr; |
| } |
| |
| return result; |
| } |
| |
| zx_status_t ralloc_get_specific_region_ex(ralloc_allocator_t* allocator, |
| const ralloc_region_t* requested_region, |
| const ralloc_region_t** out_region) { |
| if (!allocator || !requested_region || !out_region) |
| return ZX_ERR_INVALID_ARGS; |
| |
| RegionAllocator::Region::UPtr managed_region; |
| RegionAllocator& alloc = *(reinterpret_cast<RegionAllocator*>(allocator)); |
| zx_status_t result = alloc.GetRegion(*requested_region, managed_region); |
| |
| if (result == ZX_OK) { |
| // Everything looks good. Detach the managed_region our unique_ptr<> |
| // and send the unmanaged pointer to the inner ralloc_region_t back |
| // to the caller. |
| ZX_DEBUG_ASSERT(managed_region != nullptr); |
| const RegionAllocator::Region* raw_region = managed_region.release(); |
| *out_region = static_cast<const ralloc_region_t*>(raw_region); |
| } else { |
| ZX_DEBUG_ASSERT(managed_region == nullptr); |
| *out_region = nullptr; |
| } |
| |
| return result; |
| } |
| |
| size_t ralloc_get_allocated_region_count(const ralloc_allocator_t* allocator) { |
| ZX_DEBUG_ASSERT(allocator != nullptr); |
| const RegionAllocator& alloc = *(reinterpret_cast<const RegionAllocator*>(allocator)); |
| return alloc.AllocatedRegionCount(); |
| } |
| |
| size_t ralloc_get_available_region_count(const ralloc_allocator_t* allocator) { |
| ZX_DEBUG_ASSERT(allocator != nullptr); |
| const RegionAllocator& alloc = *(reinterpret_cast<const RegionAllocator*>(allocator)); |
| return alloc.AvailableRegionCount(); |
| } |
| |
| void ralloc_put_region(const ralloc_region_t* region) { |
| ZX_DEBUG_ASSERT(region); |
| |
| // Reclaim our reference back from the land of C by turning the pointer |
| // back into a unique_ptr, then deliberately let it go out of scope, destroying the |
| // RegionAllocator::Region in the process.. |
| auto raw_region = static_cast<const RegionAllocator::Region*>(region); |
| RegionAllocator::Region::UPtr release_me(raw_region); |
| } |
| |
| zx_status_t ralloc_walk_allocated_regions(const ralloc_allocator_t* allocator, region_walk_cb cb, |
| void* ctx) { |
| ZX_DEBUG_ASSERT(allocator != nullptr); |
| if (cb == NULL) { |
| return ZX_ERR_INVALID_ARGS; |
| } |
| |
| const RegionAllocator& alloc = *(reinterpret_cast<const RegionAllocator*>(allocator)); |
| alloc.WalkAllocatedRegions([cb, ctx](const ralloc_region_t* r) -> bool { return cb(r, ctx); }); |
| |
| return ZX_OK; |
| } |
| |
| } // extern "C" |