1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
//! # FFI bindings to **libpmem**
//!
//! Rust bindings for the NVM Library [http://pmem.io](http://pmem.io)
//!
//! The **pmem** library provides low level persistent memory support.
//! The libraries above are implemented using **pmem**.
//! Developers wishing to roll their own persistent memory algorithms will find this library useful,
//! but most developers will likely use **pmem-obj** and let that library call **pmem** for them.
//!
//! > This is **not** an official port of the NVM Library.
//! >
//! > The official **libpmem** documentation can be found at: [http://pmem.io/nvml/libpmem/](http://pmem.io/nvml/libpmem/)

#[macro_use]
extern crate bitflags;
extern crate pmem_sys;
extern crate libc;

// Modules

pub mod persistentmap;
pub mod ptr;
pub mod nodrain;

// lib module

use ::std::mem;
use ::std::io;
use ::std::ffi::CStr;

use ::libc::c_void;
use ::libc::size_t;
use ::pmem_sys as ffi;

/// Description of the last error
///
/// The error message is thread-local; errors encountered in one thread do not affect its value in other threads.
/// Its content is significant only when the return value of the immediately preceding
/// call to a function indicated an error.
pub fn errormsg() -> Option<String> {
    unsafe {
        let reason_p = ffi::pmem_errormsg();
        if !reason_p.is_null() {
            CStr::from_ptr(reason_p).to_owned().into_string().ok()
        } else {
            None
        }
    }
}

/// Checks if an entire object consists of persistent memory
/// If `true` then it is safe to use `persist(1)` and other related functions to make changes durable for that memory range.
///
/// The implementation of `is_pmem(1)` requires a non-trivial amount of work to determine if the given range is
/// entirely persistent memory. For this reason, it is better to call `is_pmem(1)` once when a range of memory is first encountered,
/// save the result, and use the saved result to determine whether `persist()` or `msync(1)` is appropriate for flushing changes to persistence.
/// Calling `is_pmem(1)` each time changes are flushed to persistence will not perform well.
///
/// > **Warning:** Using `persist(1)` on a range where `is_pmem(1)` returns `false` may not do anything useful -- use `msync(1)` instead.
pub fn is_pmem<T>(x: &T) -> bool {
    let len = mem::size_of_val(x);
    let r = unsafe { ffi::pmem_is_pmem(x as *const _ as *const c_void, len as size_t) };
    r > 0
}

/// Force an object to be stored durably in persistent memory.
///
/// This is equivalent to calling `msync(1)` but may be more optimal
/// and will avoid calling into the kernel if possible.
/// There are no alignment restrictions on the range the object is in,
/// but `persist(1)` may expand the range as necessary to meet platform alignment requirements.
///
/// > **Warning:** Like `msync()`, there is nothing atomic or transactional about this call.
/// > Any unwritten stores in the given range will be written, but some stores may have already been written
/// > by virtue of normal cache eviction/replacement policies. Correctly written code must not depend on stores
/// > waiting until `persist(1)` is called to become persistent -- they can become persistent at
/// > any time before `persist(1)` is called.
///
/// To create your own variations of `persist(1)`, see `flush(1)` and `drain()`. One can think of `persist(1)` as:
///
/// ```no_run
/// fn persist<T>(x: &T) {
///     // flush the processor caches
///     pmem::flush(x);
///
///     // wait for any pmem stores to drain from HW buffers
///     pmem::drain();
/// }
/// ```
pub fn persist<T>(x: &T) {
    let len = mem::size_of_val(x);
    unsafe { ffi::pmem_persist(x as *const _ as *const c_void, len as size_t) };
}

/// Forces any changes in an object to be stored durably.
///
/// This function works on either persistent memory or a memory mapped file on traditional storage.
/// `msync()` takes steps to ensure the alignment of addresses and lengths passed down meet the requirements of that system call.
/// It calls msync() with the MS_SYNC flag as described in msync(2).
/// Typically the application only checks for the existence of persistent memory once,
/// and then uses that result throughout the program, for example:
///
/// # Example
///
/// ```no_run
/// fn some_method<T>(x: &T) {
///     // do this call once, after the pmem is memory mapped
///     let is_pmem = pmem::is_pmem(x);
///
///     // ...make some changes to x
///
///     // make the changes durable
///     if is_pmem {
///         pmem::persist(&x);
///     } else{
///         pmem::msync(&x).unwrap();
///     }
/// }
/// ```
pub fn msync<T>(x: &T) -> Result<(), io::Error> {
    let len = mem::size_of_val(x);
    let r = unsafe { ffi::pmem_msync(x as *const _ as *const c_void, len as size_t) };
    if r == -1 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

/// Flushes the processor caches
///
/// This is the first of two steps in flushing to persistence,
/// the second stpe is `drain()`.
///
/// These steps are performed together when `persist()` is called.
///
/// > Note that either of these steps may be unnecessary on a given platform, and
/// > the library knows how to check for that and do the right thing.
/// > For example, on Intel platforms, pmem_drain() is an empty function.
pub fn flush<T>(x: &T) {
    let len = mem::size_of_val(x);
    unsafe { ffi::pmem_flush(x as *const _ as *const c_void, len as size_t) };
}

/// Waits for any pmem stores to drain from HW buffers
///
/// This is the second of two steps in flushing to persistence,
/// the first step is `flush(1)`.
///
/// These steps are performed together when `persist(1)` is called.
///
/// > Note that either of these steps may be unnecessary on a given platform, and
/// > the library knows how to check for that and do the right thing.
/// > For example, on Intel platforms, pmem_drain() is an empty function.
pub fn drain() { unsafe { ffi::pmem_drain() }; }

/// Wether or not the machine supports an explicit hardware drain instruction for persistent memory.
///
/// On Intel processors with persistent memory, stores to persistent memory are considered persistent
/// once they are flushed from the CPU caches, so this function always returns false.
///
/// Despite that, programs using `flush(1)` to flush ranges of memory should still follow up by calling `drain()`
// once to ensure the flushes are complete. As mentioned above, `persist(1)` handles calling both `flush(1)` and `drain()`.
pub fn has_hw_drain() -> bool {
    let r = unsafe { ffi::pmem_has_hw_drain() };
    r > 0
}