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
SharedBuffer
s 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§
Sourcepub unsafe fn new(buf: *mut u8, len: usize) -> SharedBuffer
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.
Sourcepub fn read(&self, dst: &mut [u8]) -> usize
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.
Sourcepub fn read_at(&self, offset: usize, dst: &mut [u8]) -> usize
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.
Sourcepub fn write(&self, src: &[u8]) -> usize
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.
Sourcepub fn write_at(&self, offset: usize, src: &[u8]) -> usize
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.
Sourcepub fn acquire_writes(&self)
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.
Sourcepub fn release_writes(&mut self)
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.
Sourcepub fn slice<'a, R: RangeBounds<usize>>(
&'a self,
range: R,
) -> SharedBufferSlice<'a>
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).
Sourcepub fn slice_mut<'a, R: RangeBounds<usize>>(
&'a mut self,
range: R,
) -> SharedBufferSliceMut<'a>
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).
Sourcepub fn split_at<'a>(
&'a self,
idx: usize,
) -> (SharedBufferSlice<'a>, SharedBufferSlice<'a>)
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()
.
Sourcepub fn split_at_mut<'a>(
&'a mut self,
idx: usize,
) -> (SharedBufferSliceMut<'a>, SharedBufferSliceMut<'a>)
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()
.
Sourcepub fn as_ptr_len(&mut self) -> (*mut u8, usize)
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…).