pub struct DeviceBuffer { /* private fields */ }Expand description
An owning handle to a single device allocation.
§Ownership & lifetime
A DeviceBuffer is the sole owner of the allocation it names. It is
produced only by ExecutionProvider::allocate and released only by
ExecutionProvider::deallocate, which consumes it by value. The owning
EP is both allocator and deallocator: the buffer records the DeviceId
(hence which EP instance) that may free it, so a buffer must never be handed
to a different EP. Ownership is unique — no two DeviceBuffers ever alias
the same allocation.
§No Drop
DeviceBuffer deliberately does not implement Drop. Freeing device
memory generally needs the EP’s context/stream (a CUDA context, an MLX
queue, an allocator arena) that this bare handle does not carry, so a silent
drop could not free correctly. Consequences:
- Dropping a
DeviceBufferwithout passing it todeallocateleaks the allocation. It can never double-free, which is the memory-safety property we prioritize (plan §4.4). - The session layer owns the discipline of pairing every
allocatewith exactly onedeallocate. Higher layers may wrap this handle in an RAII/Arctype that calls back into the EP; that policy lives above the EP contract, not here.
§Access
The base address is reachable only through DeviceBuffer::as_ptr
(shared) and DeviceBuffer::as_mut_ptr (unique). Obtaining a pointer is
safe; dereferencing it is unsafe and valid only on host-accessible
devices (DeviceType::is_host_accessible) within the owning EP’s context.
§Thread-safety
See the Send/Sync impls below for the exact invariant.
Implementations§
Source§impl DeviceBuffer
impl DeviceBuffer
Sourcepub unsafe fn from_raw_parts(
ptr: *mut c_void,
device: DeviceId,
size: usize,
align: usize,
) -> Self
pub unsafe fn from_raw_parts( ptr: *mut c_void, device: DeviceId, size: usize, align: usize, ) -> Self
Wrap a raw device allocation in an owning handle.
§Safety
The caller (the owning EP) must guarantee all of:
ptris non-null and points to the start of an allocation of at leastsizebytes ondevice, aligned to at leastalignbytes.- The allocation was produced by
device’s EP and will be freed exactly once, only by returning this handle to that EP’sdeallocate(or via an equivalent raw free of the pointer obtained fromDeviceBuffer::into_raw). - No other live
DeviceBufferaliases the same allocation.
align must be a power of two (checked in debug builds).
Sourcepub unsafe fn from_borrowed_parts(
ptr: *mut c_void,
device: DeviceId,
size: usize,
align: usize,
) -> Self
pub unsafe fn from_borrowed_parts( ptr: *mut c_void, device: DeviceId, size: usize, align: usize, ) -> Self
Wrap foreign, borrowed memory in a non-owning DeviceBuffer.
Unlike DeviceBuffer::from_raw_parts, the returned handle does not
own the allocation: it aliases memory owned by someone else (for example
a memmap2::Mmap over an on-disk weight file). This lets an EP reference
initializer bytes zero-copy instead of allocating + copying them into
fresh RAM.
is_borrowed returns true, and the owning
EP’s deallocate must treat it as a no-op free (the guard checks
is_borrowed()). into_raw still yields the
raw pointer, but the caller must not free it.
§Safety
The caller must guarantee all of:
ptris non-null and points to the start of a readable region of at leastsizebytes ondevice, aligned to at leastalignbytes.- The memory is owned by another object (e.g. an mmap) that outlives
this buffer and every use of it (read via
as_ptr). Nothing else may free or unmap it while this handle or any alias derived from it lives. - The buffer is treated as read-only: it is never written through
(
as_mut_ptrmust not be used to mutate borrowed memory) and is never passed to an EP’sdeallocateexpecting a free —deallocateskips the free for borrowed buffers.
align must be a power of two (checked in debug builds).
Sourcepub unsafe fn from_borrowed_mut_parts(
ptr: *mut c_void,
device: DeviceId,
size: usize,
align: usize,
) -> Option<Self>
pub unsafe fn from_borrowed_mut_parts( ptr: *mut c_void, device: DeviceId, size: usize, align: usize, ) -> Option<Self>
Wrap foreign memory in a non-owning, exclusively writable buffer handle.
This is intended for persistent external output bindings: the real owner retains the allocation while an executor temporarily writes through this alias.
§Safety
The caller must guarantee all of:
ptrnames a non-null writable allocation of at leastsizebytes ondevice, aligned to at leastalignbytes.- The real owner outlives this handle and every operation using it.
- No other writer accesses the allocation while this handle is live.
- This handle is never used to free the allocation;
deallocatetreats it as borrowed.
Sourcepub fn is_borrowed(&self) -> bool
pub fn is_borrowed(&self) -> bool
Whether this handle merely borrows (aliases) foreign memory rather than
owning it. A borrowed buffer must never be freed by deallocate.
Sourcepub fn device(&self) -> DeviceId
pub fn device(&self) -> DeviceId
The device this allocation lives on (and whose EP must free it).
Sourcepub fn as_ptr(&self) -> *const c_void
pub fn as_ptr(&self) -> *const c_void
Shared base pointer. Safe to obtain; dereferencing is unsafe and only
sound on host-accessible devices within the owning EP’s context.
Sourcepub fn as_mut_ptr(&mut self) -> *mut c_void
pub fn as_mut_ptr(&mut self) -> *mut c_void
Unique mutable base pointer. Requires &mut self so the borrow checker
forbids two writers sharing one buffer — this is what makes the Sync
impl sound (a shared &DeviceBuffer can never hand out a writable
pointer through safe code).
Sourcepub fn into_raw(self) -> *mut c_void
pub fn into_raw(self) -> *mut c_void
Consume the handle, returning the raw pointer without freeing it. For
an owned buffer the caller assumes the single-free obligation from
DeviceBuffer::from_raw_parts. For a borrowed buffer (see
DeviceBuffer::from_borrowed_parts) the pointer must not be freed;
check is_borrowed first if the caller
intends to free.