[][src]Trait crndm::alloc::MemPool

pub unsafe trait MemPool where
    Self: 'static + Sized
{ pub unsafe fn pre_alloc(size: usize) -> (*mut u8, u64, usize);
pub unsafe fn pre_dealloc(ptr: *mut u8, size: usize);
pub unsafe fn pre_realloc(
        ptr: *mut *mut u8,
        size: usize,
        new_size: usize
    ) -> bool; pub fn open_no_root(_path: &str, _flags: u32) -> Result<Self> { ... }
pub unsafe fn close() -> Result<()> { ... }
pub fn open<'a, U: 'a + PSafe + RootObj<Self>>(
        _path: &str,
        _flags: u32
    ) -> Result<RootCell<'a, U, Self>> { ... }
pub unsafe fn format(_path: &str) -> Result<()> { ... }
pub unsafe fn apply_flags(path: &str, flags: u32) -> Result<()> { ... }
pub fn allocated(_off: u64, _len: usize) -> bool { ... }
pub unsafe fn off_unchecked<T: ?Sized>(x: *const T) -> u64 { ... }
pub unsafe fn get_unchecked<'a, T: 'a + ?Sized>(off: u64) -> &'a T { ... }
pub unsafe fn get_mut_unchecked<'a, T: 'a + ?Sized>(off: u64) -> &'a mut T { ... }
pub unsafe fn deref_slice_unchecked<'a, T: 'a>(
        off: u64,
        len: usize
    ) -> &'a [T] { ... }
pub unsafe fn deref_slice_unchecked_mut<'a, T: 'a>(
        off: u64,
        len: usize
    ) -> &'a mut [T] { ... }
pub unsafe fn deref<'a, T: 'a>(off: u64) -> Result<&'a T> { ... }
pub unsafe fn deref_mut<'a, T: 'a>(off: u64) -> Result<&'a mut T> { ... }
pub fn off<T: ?Sized>(x: *const T) -> Result<u64> { ... }
pub fn rng() -> Range<u64> { ... }
pub fn start() -> u64 { ... }
pub fn end() -> u64 { ... }
pub fn size() -> usize { ... }
pub fn available() -> usize { ... }
pub fn used() -> usize { ... }
pub fn valid<T: ?Sized>(p: &T) -> bool { ... }
pub fn contains(addr: u64) -> bool { ... }
pub unsafe fn alloc(size: usize) -> (*mut u8, u64, usize) { ... }
pub unsafe fn dealloc(ptr: *mut u8, size: usize) { ... }
pub unsafe fn log64(_obj: *const u64, _val: u64) { ... }
pub unsafe fn drop_on_failure(_off: u64, _len: usize) { ... }
pub unsafe fn perform() { ... }
pub unsafe fn discard() { ... }
pub unsafe fn alloc_zeroed(size: usize) -> *mut u8 { ... }
pub unsafe fn realloc(
        ptr: *mut *mut u8,
        size: usize,
        new_size: usize
    ) -> bool { ... }
pub unsafe fn new<'a, T: PSafe + 'a>(x: T, j: &Journal<Self>) -> &'a mut T { ... }
pub unsafe fn new_slice<'a, T: PSafe + 'a>(
        x: &'a [T],
        _journal: &Journal<Self>
    ) -> &'a mut [T] { ... }
pub unsafe fn atomic_new<'a, T: 'a>(x: T) -> (&'a mut T, u64, usize) { ... }
pub unsafe fn atomic_new_slice<'a, T: 'a + PSafe>(
        x: &'a [T]
    ) -> (&'a mut [T], u64, usize) { ... }
pub unsafe fn new_uninit<'a, T: PSafe + 'a>(j: &Journal<Self>) -> &'a mut T { ... }
pub unsafe fn new_uninit_for_layout(
        size: usize,
        journal: &Journal<Self>
    ) -> *mut u8 { ... }
pub unsafe fn atomic_new_uninit<'a, T: 'a>() -> (&'a mut T, u64, usize) { ... }
pub unsafe fn alloc_for_value<'a, T: ?Sized>(x: &T) -> &'a mut T { ... }
pub unsafe fn free<'a, T: PSafe + ?Sized>(x: &mut T) { ... }
pub unsafe fn free_slice<'a, T: PSafe>(x: &mut [T]) { ... }
pub unsafe fn free_nolog<'a, T: ?Sized>(x: &T) { ... }
pub unsafe fn guarded<T, F: FnOnce() -> T>(f: F) -> T { ... }
pub unsafe fn new_journal(_tid: ThreadId) { ... }
pub unsafe fn drop_journal(_journal: &mut Journal<Self>) { ... }
pub unsafe fn journals(
    ) -> &'static mut HashMap<ThreadId, (&'static Journal<Self>, i32)> { ... }
pub unsafe fn recover() { ... }
pub unsafe fn commit() { ... }
pub unsafe fn commit_no_clear() { ... }
pub unsafe fn clear() { ... }
pub unsafe fn rollback() { ... }
pub unsafe fn rollback_no_clear() { ... }
pub fn transaction<T, F: FnOnce(&Journal<Self>) -> T>(body: F) -> Result<T>
    where
        F: TxInSafe + UnwindSafe,
        T: TxOutSafe
, { ... }
pub fn gen() -> u32 { ... }
pub fn print_info() { ... } }

Persistent Memory Pool

This trait can be used to define a persistent memory pool type. The methods of MemPool trait do not have a reference to self in order to make sure that all information that it works with, including the virtual address boundaries, are static. Therefore, all objects with the same memory allocator will share a unique memory pool type. Having a strong set of type checking rules, Rust prevents referencing from one memory pool to another.

To implement a new memory pool, you should define a new type with static values, that implements MemPool. You may use static_inner_object!() to statically define allocator's inner data, and static_inner!() to access it. You may also use the default allocator using pool!() which creates a pool module with a default allocator of type BuddyAlloc.

Examples

The following example shows how to use MemPool to track allocations of a single numerical object of type i32.

use std::alloc::{alloc,dealloc,realloc,Layout};

struct TrackAlloc {}

unsafe impl MemPool for TrackAlloc {
    fn rng() -> Range<u64> { 0..u64::MAX }
    unsafe fn pre_alloc(size: usize) -> (*mut u8, u64, usize) {
        let p = alloc(Layout::from_size_align_unchecked(size, 4));
        println!("A block of {} bytes is allocated at {}", size, p as u64);
        (p, p as u64, size)
    }
    unsafe fn pre_dealloc(p: *mut u8, size: usize) {
        println!("A block of {} bytes at {} is deallocated", size, p as u64);
        dealloc(p, Layout::from_size_align_unchecked(size, 1));
    }
    unsafe fn pre_realloc(p: *mut *mut u8, old: usize, new: usize) -> bool {
        println!("A block of {} bytes at {} is reallocated to {}", old, *p as u64, new);
        *p = realloc(*p, Layout::from_size_align_unchecked(old, 1), new);
        true
    }
}

unsafe {
    let (p, _, _) = TrackAlloc::alloc(1);
    *p = 10;
    println!("loc {} contains {}", p as u64, *p);
    TrackAlloc::dealloc(p, 1);
}

Safety

This is the developer's responsibility to manually drop allocated objects. One way for memory management is to use pointer wrappers that implement Drop trait and deallocate the object on drop. Unsafe methods does not guarantee persistent memory safety.

pmem crate provides Pbox, Prc, and Parc for memory management using RAII. They internally use the unsafe methods.

Required methods

pub unsafe fn pre_alloc(size: usize) -> (*mut u8, u64, usize)[src]

Prepares allocation without performing it

This function is used internally for low-level atomicity in memory allocation. See Log::set() for more details.

Examples

unsafe {
    let (ptr, _, _) = P::pre_alloc(8);
    *ptr = 10;
    P::perform();
}

pub unsafe fn pre_dealloc(ptr: *mut u8, size: usize)[src]

Prepares deallocation without performing it

This function is used internally for low-level atomicity in memory allocation. See Log::set() for more details.

Examples

unsafe {
    let (ptr, _, _) = P::alloc(8);
    *ptr = 10;
    P::pre_dealloc(ptr, 8);
    assert_eq!(*ptr, 10);
    P::perform();
    assert_ne!(*ptr, 10);
}

pub unsafe fn pre_realloc(
    ptr: *mut *mut u8,
    size: usize,
    new_size: usize
) -> bool
[src]

Prepares reallocation without performing it, updating the pointer to a new one, if required, with a new size

Examples

unsafe {
    let (mut ptr, _, _) = P::alloc(8);
    P::pre_realloc(&mut ptr, 8, 16);
    P::perform();
    P::dealloc(ptr, 16);
}
Loading content...

Provided methods

pub fn open_no_root(_path: &str, _flags: u32) -> Result<Self>[src]

Opens a new pool without any root object. This function is for testing and is not useful in real applications as none of the allocated objects in persistent region is durable. The reason is that they are not reachable from a root object as it doesn't exists. All objects can live only in the scope of a transaction.

Flags

  • O_C: create a memory pool file if not exists
  • O_F: format the memory pool file
  • O_CNE: create a memory pool file if not exists
  • O_CF: create and format a new memory pool file
  • O_CFNE: create and format a memory pool file only if not exists

See open_flags for more options.

pub unsafe fn close() -> Result<()>[src]

Commits all changes and clears the logs for all threads

This method should be called while dropping the MemPool object to make sure that all uncommitted changes outside transactions, such as reference counters, are persistent.

pub fn open<'a, U: 'a + PSafe + RootObj<Self>>(
    _path: &str,
    _flags: u32
) -> Result<RootCell<'a, U, Self>>
[src]

Opens a pool and retrieves the root object

The root type should implement RootObj trait in order to create a root object on its absence. This function [creates and] returns an immutable reference to the root object. The pool remains open as long as the root object is in the scope. Like other persistent objects, the root object is immutable and it is modifiable via interior mutability.

Flags

  • O_C: create a memory pool file if not exists
  • O_F: format the memory pool file
  • O_CNE: create a memory pool file if not exists
  • O_CF: create and format a new memory pool file
  • O_CFNE: create and format a memory pool file only if not exists

See open_flags for more options.

Examples

use crndm::default::*;

let root = BuddyAlloc::open::<i32>("foo.pool", O_CF).unwrap();

assert_eq!(*root, i32::default());

Single-thread Shared Root Object

Prc<PCell<T>> can be used in order to have a mutable shared root object, as follows.

use crndm::default::*;

type Root = Prc<PCell<i32>>;

let root = BuddyAlloc::open::<Root>("foo.pool", O_CF).unwrap();

let data = root.get();

if data == i32::default() {
    println!("Initializing data");
    // This block runs only once to initialize the root object
    transaction(|j| {
        root.set(10, j);
    }).unwrap();
}

assert_eq!(root.get(), 10);

Thread-safe Root Object

If you need a thread-safe root object, you may want to wrap the root object in Parc<PMutex<T>>, as shown in the example below:

use crndm::default::*;
use std::thread;

type Root = Parc<PMutex<i32>>;

let root = BuddyAlloc::open::<Root>("foo.pool", O_CF).unwrap();

let mut threads = vec!();

for _ in 0..10 {
    let root = Parc::volatile(&root);
    threads.push(thread::spawn(move || {
        transaction(|j| {
            if let Some(root) = root.upgrade(j) {
                let mut root = root.lock(j);
                *root += 10;
            }
        }).unwrap();
    }));
}

for thread in threads {
    thread.join().unwrap();
}

transaction(|j| {
    let data = root.lock(j);
    assert_eq!(*data % 100, 0);
}).unwrap();

Errors

  • A volatile memory pool (e.g. Heap) doesn't have a root object.
  • The pool should be open before accessing the root object.

pub unsafe fn format(_path: &str) -> Result<()>[src]

Formats the memory pool file

pub unsafe fn apply_flags(path: &str, flags: u32) -> Result<()>[src]

Applies open pool flags

pub fn allocated(_off: u64, _len: usize) -> bool[src]

Indicates if the given offset is allocated

pub unsafe fn off_unchecked<T: ?Sized>(x: *const T) -> u64[src]

Translates raw pointers to memory offsets

Safety

The raw pointer should be in the valid range

pub unsafe fn get_unchecked<'a, T: 'a + ?Sized>(off: u64) -> &'a T[src]

Acquires a reference pointer to the object

Safety

The offset should be in the valid address range

pub unsafe fn get_mut_unchecked<'a, T: 'a + ?Sized>(off: u64) -> &'a mut T[src]

Acquires a mutable reference to the object

Safety

The offset should be in the valid address range

pub unsafe fn deref_slice_unchecked<'a, T: 'a>(off: u64, len: usize) -> &'a [T][src]

Acquires a reference to the slice

Safety

The offset should be in the valid address range

pub unsafe fn deref_slice_unchecked_mut<'a, T: 'a>(
    off: u64,
    len: usize
) -> &'a mut [T]
[src]

Acquires a mutable reference to the slice

Safety

The offset should be in the valid address range

pub unsafe fn deref<'a, T: 'a>(off: u64) -> Result<&'a T>[src]

Acquires a reference to the object

pub unsafe fn deref_mut<'a, T: 'a>(off: u64) -> Result<&'a mut T>[src]

Acquires a mutable reference pointer to the object

pub fn off<T: ?Sized>(x: *const T) -> Result<u64>[src]

Translates raw pointers to memory offsets

pub fn rng() -> Range<u64>[src]

Valid Virtual Address Range

pub fn start() -> u64[src]

Start of virtual address range

pub fn end() -> u64[src]

End of virtual address range

pub fn size() -> usize[src]

Total size of the memory pool

pub fn available() -> usize[src]

Available space in the pool

pub fn used() -> usize[src]

Total occupied space

pub fn valid<T: ?Sized>(p: &T) -> bool[src]

Checks if the reference p belongs to this pool

pub fn contains(addr: u64) -> bool[src]

Checks if addr is in the valid address range if this allocator

addr contains the scalar of a virtual address. If you have a raw fat pointer of type T, you can obtain its virtual address by converting it into a thin pointer and then u64.

Examples

let p = Box::new(1);
println!("Address {:#x} contains value '{}'", p.as_ref() as *const _ as u64, *p);

pub unsafe fn alloc(size: usize) -> (*mut u8, u64, usize)[src]

Allocate memory as described by the given layout.

Returns a pointer to newly-allocated memory.

Safety

This function is unsafe because undefined behavior can result if the caller does not ensure that layout has non-zero size. The allocated block of memory may or may not be initialized.

pub unsafe fn dealloc(ptr: *mut u8, size: usize)[src]

Deallocate the block of memory at the given ptr pointer with the given size.

Safety

This function is unsafe because undefined behavior can result if the caller does not ensure all of the following:

  • ptr must denote a block of memory currently allocated via this allocator,

  • size must be the same size that was used to allocate that block of memory.

pub unsafe fn log64(_obj: *const u64, _val: u64)[src]

Adds a low-level log to update as 64-bit obj to val when perform() is called. See Log::set() for more details.

pub unsafe fn drop_on_failure(_off: u64, _len: usize)[src]

Adds a low-level DropOnFailure log to perform inside the allocator. This is internally used to atomically allocate a new objects. Calling perform() drops these logs.

Examples

unsafe {
    // Prepare an allocation. The allocation is not durable yet. In case
    // of a crash, the prepared allocated space is gone. It is fine
    // because it has not been used. The `pre_` and `perform` functions
    // form a low-level atomic section.
    let (obj, off, len) = P::pre_alloc(1);
 
    // Create a low-level DropOnFailure log. This log is going to be used
    // when a crash happens while performing the changes made by the
    // preparation functions. If a crash happens before that, these logs
    // will be discarded.
    P::drop_on_failure(off, len);
     
    // It is fine to work with the prepared raw pointer. All changes in
    // the low-level atomic section are considered as part of the
    // allocation and will be gone in case of a crash, as the allocation
    // will be dropped.
    *obj = 20;
 
    // Transaction ends here. The perform function sets the `operating`
    // flag to show that the prepared changes are being materialized.
    // This flag remains set until the end of materialization. In case
    // of a crash while operating, the recovery procedure first continues
    // the materialization, and then uses the `DropOnFailure` logs to
    // reclaim the allocation.
    P::perform();
}

pub unsafe fn perform()[src]

Performs the prepared operations

Materializes the changes made by pre_alloc, pre_dealloc, and pre_realloc. See Log::set() for more details.

pub unsafe fn discard()[src]

Discards the prepared operations

Discards the changes made by pre_alloc, pre_dealloc, and pre_realloc. See Log::set() for more details.

pub unsafe fn alloc_zeroed(size: usize) -> *mut u8[src]

Behaves like alloc, but also ensures that the contents are set to zero before being returned.

Safety

This function is unsafe for the same reasons that alloc is. However the allocated block of memory is guaranteed to be initialized.

Errors

Returning a null pointer indicates that either memory is exhausted or layout does not meet allocator's size or alignment constraints, just as in alloc.

Clients wishing to abort computation in response to an allocation error are encouraged to call the handle_alloc_error function, rather than directly invoking panic! or similar.

pub unsafe fn realloc(ptr: *mut *mut u8, size: usize, new_size: usize) -> bool[src]

Shrink or grow a block of memory to the given new_size. The block is described by the given ptr pointer and layout.

If successful, it replaces the pointer location to a new value and returns true.

Safety

This function is unsafe because undefined behavior can result if the caller does not ensure all of the following:

  • ptr must be currently allocated using this allocator,

  • size must be the same size that was used to allocate that block of memory,

  • new_size must be greater than zero.

pub unsafe fn new<'a, T: PSafe + 'a>(x: T, j: &Journal<Self>) -> &'a mut T[src]

Allocates new memory and then places x into it with DropOnFailure log

pub unsafe fn new_slice<'a, T: PSafe + 'a>(
    x: &'a [T],
    _journal: &Journal<Self>
) -> &'a mut [T]
[src]

Allocates a new slice and then places x into it with DropOnAbort log

pub unsafe fn atomic_new<'a, T: 'a>(x: T) -> (&'a mut T, u64, usize)[src]

Allocates new memory and then places x into it without realizing the allocation

pub unsafe fn atomic_new_slice<'a, T: 'a + PSafe>(
    x: &'a [T]
) -> (&'a mut [T], u64, usize)
[src]

Allocates new memory and then places x into it without realizing the allocation

pub unsafe fn new_uninit<'a, T: PSafe + 'a>(j: &Journal<Self>) -> &'a mut T[src]

Allocates new memory without copying data

pub unsafe fn new_uninit_for_layout(
    size: usize,
    journal: &Journal<Self>
) -> *mut u8
[src]

Allocates new memory without copying data

pub unsafe fn atomic_new_uninit<'a, T: 'a>() -> (&'a mut T, u64, usize)[src]

Allocates new memory without copying data and realizing the allocation

pub unsafe fn alloc_for_value<'a, T: ?Sized>(x: &T) -> &'a mut T[src]

Allocates new memory for value x

pub unsafe fn free<'a, T: PSafe + ?Sized>(x: &mut T)[src]

Creates a DropOnCommit log for the value x

pub unsafe fn free_slice<'a, T: PSafe>(x: &mut [T])[src]

Creates a DropOnCommit log for the value x

pub unsafe fn free_nolog<'a, T: ?Sized>(x: &T)[src]

Frees the allocation for value x

pub unsafe fn guarded<T, F: FnOnce() -> T>(f: F) -> T[src]

Executes a closure guarded by a global mutex

pub unsafe fn new_journal(_tid: ThreadId)[src]

Creates a new Journal object for the current thread

pub unsafe fn drop_journal(_journal: &mut Journal<Self>)[src]

Drops a journal from memory

pub unsafe fn journals(
) -> &'static mut HashMap<ThreadId, (&'static Journal<Self>, i32)>
[src]

Returns the list of all journals

pub unsafe fn recover()[src]

Recovers from a crash

pub unsafe fn commit()[src]

Commits all changes and clears the logs for one thread

If the transaction is nested, it postpones the commit to the top most transaction.

Safety

This function is for internal use and should not be called elsewhere.

pub unsafe fn commit_no_clear()[src]

Commits all changes without clearing the logs

If the transaction is nested, it postpones the commit to the top most transaction.

Safety

This function is for internal use and should not be called elsewhere.

pub unsafe fn clear()[src]

Clears the logs

If the transaction is nested, it postpones the clear to the top most transaction.

Safety

This function is for internal use and should not be called elsewhere.

pub unsafe fn rollback()[src]

Discards all changes and clears the logs

If the transaction is nested, it propagates the panic upto the top most transaction to make all of them tainted.

Safety

This function is for internal use and should not be called elsewhere.

pub unsafe fn rollback_no_clear()[src]

Discards all changes without clearing the logs

If the transaction is nested, it propagates the panic upto the top most transaction to make all of them tainted.

Safety

This function is for internal use and should not be called elsewhere.

pub fn transaction<T, F: FnOnce(&Journal<Self>) -> T>(body: F) -> Result<T> where
    F: TxInSafe + UnwindSafe,
    T: TxOutSafe
[src]

Executes commands atomically

The transaction function takes a closure with one argument of type &Journal<Self>. Before running the closure, it atomically creates a Journal object, if required, and prepares an immutable reference to it. Since there is no other safe way to create a Journal object, it ensures that every function taking an argument of type &Journal<P> is enforced to be invoked from a transaction.

The captured types are bounded to be TxInSafe, unless explicitly asserted otherwise using AssertTxInSafe type wrapper. This guarantees the volatile state consistency, as well as the persistent state.

The returned type should be TxOutSafe. This prevents sending out unreachable persistent objects. The only way out of a transaction for a persistent object is to be reachable by the root object.

Examples

use crndm::default::*;
 
type P = BuddyAlloc;
 
let root = P::open::<PCell<i32>>("foo.pool", O_CF).unwrap();
 
let old = root.get();
let new = BuddyAlloc::transaction(|j| {
    root.set(root.get() + 1, j);
    root.get()
}).unwrap();
 
assert_eq!(new, old + 1);

pub fn gen() -> u32[src]

pub fn print_info()[src]

Prints memory information

Loading content...

Implementors

impl MemPool for BuddyAlloc[src]

pub unsafe fn format(filename: &str) -> Result<()>[src]

Formats the image file

impl MemPool for Heap[src]

Loading content...