blob: 694f927087f4f16c707c5d6691b7fe038b4a2639 [file]
// Copyright 2016 The Fuchsia Authors
// Copyright (c) 2015 Google, Inc. All rights reserved
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
//! FFI bindings for `cmpctmalloc` (used by host userspace C++ tests).
use core::ffi::c_void;
use super::cmpctmalloc::{
HEAP_MAX_ALLOC_SIZE, cmpct_alloc, cmpct_free, cmpct_get_cookie, cmpct_get_info, cmpct_get_size,
cmpct_init, cmpct_memalign, cmpct_set_cookie, cmpct_set_fill_on_alloc_threshold,
cmpct_sized_free,
};
/// C-visible maximum allocation size (`kHeapMaxAllocSize`).
// SAFETY: The symbol name is unique and matches the C FFI declaration in cmpctmalloc.h.
#[unsafe(no_mangle)]
pub static kHeapMaxAllocSize: usize = HEAP_MAX_ALLOC_SIZE;
unsafe extern "C" {
/// Allocates `pages` contiguous pages from the VM for the heap.
///
/// # Safety
///
/// The caller must ensure that `TheHeapLock` is held and `pages > 0`.
pub fn heap_page_alloc(pages: usize) -> *mut c_void;
/// Returns `pages` contiguous pages starting at `ptr` to the VM.
///
/// # Safety
///
/// The caller must ensure that `TheHeapLock` is held, `ptr` is a page-aligned pointer
/// previously returned by `heap_page_alloc`, and `pages > 0`.
pub fn heap_page_free(ptr: *mut c_void, pages: usize);
/// Reports a heap allocation failure of `size` bytes to the PMM.
///
/// # Safety
///
/// The caller must ensure that `TheHeapLock` is not held on the current thread.
pub fn heap_report_alloc_failure(size: usize);
}
/// FFI entry point for [`cmpct_alloc`].
///
/// # Safety
///
/// The caller must ensure that `TheHeapLock` is not held on the current thread and the heap has
/// been initialized via [`rust_cmpct_init`].
// SAFETY: The symbol name is unique and matches the C FFI declaration in cmpctmalloc_ffi.h.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust_cmpct_alloc(size: usize) -> *mut c_void {
// SAFETY: Caller upholds the safety requirements of `cmpct_alloc`.
unsafe { cmpct_alloc(size) }
}
/// FFI entry point for [`cmpct_free`].
///
/// # Safety
///
/// The caller must ensure that `payload` is either null or a pointer previously returned by
/// `cmpct_alloc` or `cmpct_memalign` that has not yet been freed, and `TheHeapLock` is not held.
// SAFETY: The symbol name is unique and matches the C FFI declaration in cmpctmalloc_ffi.h.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust_cmpct_free(payload: *mut c_void) {
// SAFETY: Caller upholds the safety requirements of `cmpct_free`.
unsafe { cmpct_free(payload) }
}
/// FFI entry point for [`cmpct_sized_free`].
///
/// # Safety
///
/// The caller must ensure that `payload` is either null or a pointer previously returned by
/// `cmpct_alloc` or `cmpct_memalign` with size `s` that has not yet been freed, and `TheHeapLock`
/// is not held.
// SAFETY: The symbol name is unique and matches the C FFI declaration in cmpctmalloc_ffi.h.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust_cmpct_sized_free(payload: *mut c_void, s: usize) {
// SAFETY: Caller upholds the safety requirements of `cmpct_sized_free`.
unsafe { cmpct_sized_free(payload, s) }
}
/// FFI entry point for [`cmpct_memalign`].
///
/// # Safety
///
/// The caller must ensure that `alignment` is a power of two (or `< 8`), `TheHeapLock` is not
/// held on the current thread, and the heap has been initialized via [`rust_cmpct_init`].
// SAFETY: The symbol name is unique and matches the C FFI declaration in cmpctmalloc_ffi.h.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust_cmpct_memalign(alignment: usize, size: usize) -> *mut c_void {
// SAFETY: Caller upholds the safety requirements of `cmpct_memalign`.
unsafe { cmpct_memalign(alignment, size) }
}
/// FFI entry point for [`cmpct_set_fill_on_alloc_threshold`].
// SAFETY: The symbol name is unique and matches the C FFI declaration in cmpctmalloc_ffi.h.
#[unsafe(no_mangle)]
pub extern "C" fn rust_cmpct_set_fill_on_alloc_threshold(size: usize) {
cmpct_set_fill_on_alloc_threshold(size);
}
/// FFI entry point for [`cmpct_init`].
///
/// # Safety
///
/// The caller must ensure that `TheHeapLock` is not held and no concurrent heap operations are
/// in flight.
// SAFETY: The symbol name is unique and matches the C FFI declaration in cmpctmalloc_ffi.h.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust_cmpct_init() {
// SAFETY: Caller upholds the safety requirements of `cmpct_init`.
unsafe { cmpct_init() }
}
/// FFI entry point for [`cmpct_get_info`].
///
/// # Safety
///
/// The caller must ensure that each non-null pointer among `used_bytes`, `free_bytes`, and
/// `cached_bytes` is properly aligned and valid for writes of `size_of::<usize>()` bytes.
// SAFETY: The symbol name is unique and matches the C FFI declaration in cmpctmalloc_ffi.h.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust_cmpct_get_info(
used_bytes: *mut usize,
free_bytes: *mut usize,
cached_bytes: *mut usize,
) {
let info = cmpct_get_info();
// SAFETY: Caller guarantees each non-null pointer is aligned and valid for writes.
unsafe {
if !used_bytes.is_null() {
used_bytes.write(info.used_bytes);
}
if !free_bytes.is_null() {
free_bytes.write(info.free_bytes);
}
if !cached_bytes.is_null() {
cached_bytes.write(info.cached_bytes);
}
}
}
/// FFI entry point for [`cmpct_set_cookie`].
///
/// # Safety
///
/// The caller must ensure that `ptr` is non-null and points to a live allocation currently owned
/// by the caller (returned by `cmpct_alloc` or `cmpct_memalign` and not yet freed), with no
/// concurrent access to its header cookie.
// SAFETY: The symbol name is unique and matches the C FFI declaration in cmpctmalloc_ffi.h.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust_cmpct_set_cookie(ptr: *mut c_void, cookie: u32) {
// SAFETY: Caller guarantees `ptr` is a live non-null allocation payload pointer.
unsafe { cmpct_set_cookie(ptr, cookie) }
}
/// FFI entry point for [`cmpct_get_cookie`].
///
/// # Safety
///
/// The caller must ensure that `ptr` is non-null and points to a live allocation currently owned
/// by the caller (returned by `cmpct_alloc` or `cmpct_memalign` and not yet freed), with no
/// concurrent mutation of its header cookie.
// SAFETY: The symbol name is unique and matches the C FFI declaration in cmpctmalloc_ffi.h.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust_cmpct_get_cookie(ptr: *mut c_void) -> u32 {
// SAFETY: Caller guarantees `ptr` is a live non-null allocation payload pointer.
unsafe { cmpct_get_cookie(ptr) }
}
/// FFI entry point for [`cmpct_get_size`].
///
/// # Safety
///
/// The caller must ensure that `ptr` is non-null and points to a live allocation currently owned
/// by the caller (returned by `cmpct_alloc` or `cmpct_memalign` and not yet freed).
// SAFETY: The symbol name is unique and matches the C FFI declaration in cmpctmalloc_ffi.h.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust_cmpct_get_size(ptr: *mut c_void) -> u32 {
// SAFETY: Caller guarantees `ptr` is a live non-null allocation payload pointer.
unsafe { cmpct_get_size(ptr) }
}