pub struct SharedBuffer { /* private fields */ }
Expand description

A shared region of memory.

A SharedBuffer is a view into a region of memory to which another process has access. It provides methods to access this memory in a way that preserves memory safety. From the perspective of the current process, it owns its memory (analogous to a Vec).

Since the buffer is shared by an untrusted process, it is never valid to assume that a given region of the buffer will not change in between method calls. Even if no thread in this process wrote anything to the buffer, the other process might have.

§Unmapping

SharedBuffers do nothing when dropped. In order to avoid leaking memory, use the consume method to consume the SharedBuffer and get back the underlying pointer and length, and unmap the memory manually.

Implementations§

source§

impl SharedBuffer

source

pub unsafe fn new(buf: *mut u8, len: usize) -> SharedBuffer

Create a new SharedBuffer from a raw buffer.

new creates a new SharedBuffer from the provided buffer and lenth, taking ownership of the memory.

§Safety

Memory in a shared buffer must never be accessed except through the methods of SharedBuffer. It must not be treated as normal memory, and pointers to it must not be passed to unsafe code which is designed to operate on normal memory. It must be guaranteed that, for the lifetime of the SharedBuffer, the memory region is mapped, readable, and writable.

If any of these guarantees are violated, it may cause undefined behavior.

source

pub fn read(&self, dst: &mut [u8]) -> usize

Read bytes from the buffer.

Read up to dst.len() bytes from the buffer, returning how many bytes were read. The only thing that can cause fewer bytes to be read than requested is if dst is larger than the buffer itself.

A call to read is only guaranteed to happen after an operation in another thread or process if the mechanism used to signal the other process has well-defined memory ordering semantics. Otherwise, the acquire_writes method must be called before read and after receiving a signal from the other process in order to provide such ordering guarantees. In practice, this means that acquire_writes should be the first read operation that happens after receiving a signal from another process that the memory may be read. See the acquire_writes documentation for more details.

source

pub fn read_at(&self, offset: usize, dst: &mut [u8]) -> usize

Read bytes from the buffer at an offset.

Read up to dst.len() bytes starting at offset into the buffer, returning how many bytes were read. The only thing that can cause fewer bytes to be read than requested is if there are fewer than dst.len() bytes available starting at offset within the buffer.

A call to read_at is only guaranteed to happen after an operation in another thread or process if the mechanism used to signal the other process has well-defined memory ordering semantics. Otherwise, the acquire_writes method must be called before read_at and after receiving a signal from the other process in order to provide such ordering guarantees. In practice, this means that acquire_writes should be the first read operation that happens after receiving a signal from another process that the memory may be read. See the acquire_writes documentation for more details.

§Panics

read_at panics if offset is greater than the length of the buffer.

source

pub fn write(&self, src: &[u8]) -> usize

Write bytes to the buffer.

Write up to src.len() bytes into the buffer, returning how many bytes were written. The only thing that can cause fewer bytes to be written than requested is if src is larger than the buffer itself.

A call to write is only guaranteed to happen before an operation in another thread or process if the mechanism used to signal the other process has well-defined memory ordering semantics. Otherwise, the release_writes method must be called after write and before signalling the other process in order to provide such ordering guarantees. In practice, this means that release_writes should be the last write operation that happens before signalling another process that the memory may be read. See the release_writes documentation for more details.

source

pub fn write_at(&self, offset: usize, src: &[u8]) -> usize

Write bytes to the buffer at an offset.

Write up to src.len() bytes starting at offset into the buffer, returning how many bytes were written. The only thing that can cause fewer bytes to be written than requested is if there are fewer than src.len() bytes available starting at offset within the buffer.

A call to write_at is only guaranteed to happen before an operation in another thread or process if the mechanism used to signal the other process has well-defined memory ordering semantics. Otherwise, the release_writes method must be called after write_at and before signalling the other process in order to provide such ordering guarantees. In practice, this means that release_writes should be the last write operation that happens before signalling another process that the memory may be read. See the release_writes documentation for more details.

§Panics

write_at panics if offset is greater than the length of the buffer.

source

pub fn acquire_writes(&self)

Acquire all writes performed by the other process.

On some systems (such as Fuchsia, currently), the communication mechanism used for signalling a process that memory is readable does not have well-defined synchronization semantics. On those systems, this method MUST be called after receiving such a signal, or else writes performed before that signal are not guaranteed to be observed by this process.

acquire_writes acquires any writes performed on this buffer or any slice within the buffer.

§Note on Fuchsia

Zircon, the Fuchsia kernel, will likely eventually have well-defined semantics around the synchronization behavior of various syscalls. Once that happens, calling this method in Fuchsia programs may become optional. This work is tracked in https://fxbug.dev/42107145.

source

pub fn release_writes(&mut self)

Release all writes performed so far.

On some systems (such as Fuchsia, currently), the communication mechanism used for signalling the other process that memory is readable does not have well-defined synchronization semantics. On those systems, this method MUST be called before such signalling, or else writes performed before that signal are not guaranteed to be observed by the other process.

release_writes releases any writes performed on this buffer or any slice within the buffer.

§Note on Fuchsia

Zircon, the Fuchsia kernel, will likely eventually have well-defined semantics around the synchronization behavior of various syscalls. Once that happens, calling this method in Fuchsia programs may become optional. This work is tracked in https://fxbug.dev/42107145.

source

pub fn len(&self) -> usize

The number of bytes in this SharedBuffer.

source

pub fn slice<'a, R: RangeBounds<usize>>( &'a self, range: R ) -> SharedBufferSlice<'a>

Create a slice of the original SharedBuffer.

Just like the slicing operation on array and slice references, slice constructs a SharedBufferSlice which points to the same memory as the original SharedBuffer, but starting and index from (inclusive) and ending at index to (exclusive).

§Panics

slice panics if range is out of bounds of self or if range is nonsensical (its lower bound is larger than its upper bound).

source

pub fn slice_mut<'a, R: RangeBounds<usize>>( &'a mut self, range: R ) -> SharedBufferSliceMut<'a>

Create a mutable slice of the original SharedBuffer.

Just like the mutable slicing operation on array and slice references, slice_mut constructs a SharedBufferSliceMut which points to the same memory as the original SharedBuffer, but starting and index from (inclusive) and ending at index to (exclusive).

§Panics

slice_mut panics if range is out of bounds of self or if range is nonsensical (its lower bound is larger than its upper bound).

source

pub fn split_at<'a>( &'a self, idx: usize ) -> (SharedBufferSlice<'a>, SharedBufferSlice<'a>)

Create two non-overlapping slices of the original SharedBuffer.

Just like the split_at method on array and slice references, split_at constructs one SharedBufferSlice which represents bytes [0, idx), and one which represents bytes [idx, len), where len is the length of the buffer.

§Panics

split_at panics if idx > self.len().

source

pub fn split_at_mut<'a>( &'a mut self, idx: usize ) -> (SharedBufferSliceMut<'a>, SharedBufferSliceMut<'a>)

Create two non-overlapping mutable slices of the original SharedBuffer.

Just like the split_at_mut method on array and slice references, split_at_miut constructs one SharedBufferSliceMut which represents bytes [0, idx), and one which represents bytes [idx, len), where len is the length of the buffer.

§Panics

split_at_mut panics if idx > self.len().

source

pub fn as_ptr_len(&mut self) -> (*mut u8, usize)

Get the buffer pointer and length so that the memory can be freed.

This method is an alternative to calling consume if relinquishing ownership of the object is infeasible (for example, when the object is a struct field and thus can’t be moved out of the struct). Since it allows the object to continue existing, it must be used with care (see the “Safety” section below).

§Safety

The returned pointer must only be used to free the memory. Since the memory is shared by another process, using it as a normal raw pointer to normal memory owned by this process is unsound.

If the pointer is used for this purpose, then the caller must ensure that no methods will be called on the object after the call to as_ptr_len. The only scenario in which the object may be used again is if the caller does nothing at all with the return value of this method (although that would be kind of pointless…).

source

pub fn consume(self) -> (*mut u8, usize)

Consume the SharedBuffer, returning the underlying buffer pointer and length.

Since SharedBuffers do nothing on drop, the only way to ensure that resources are not leaked is to consume a SharedBuffer and then unmap the memory manually.

Trait Implementations§

source§

impl Debug for SharedBuffer

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Drop for SharedBuffer

source§

fn drop(&mut self)

Executes the destructor for this type. Read more
source§

impl Send for SharedBuffer

source§

impl Sync for SharedBuffer

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.