cuda.core._memory._ipc.VirtualMemoryIPCBufferDescriptor#

class cuda.core._memory._ipc.VirtualMemoryIPCBufferDescriptor#

Serializable object describing a VirtualMemoryBuffer that can be shared between processes.

The descriptor holds one exported POSIX file descriptor per physical allocation that backs the buffer, in address order (handles, each an IPCAllocationHandle that the descriptor owns and closes when it is released), with each allocation’s size (sizes) and the buffer’s size (size, which may be smaller than their sum). handle_type is "posix_fd", the only handle type cuda.core shares today; the rules below describe file descriptors.

A descriptor pins the physical memory while it exists, in every process that holds one, and nothing else does: the exporting buffer keeps no descriptor, and an imported buffer does not keep the one it came from. A descriptor parked in a multiprocessing Queue or sent to a Pool pins the memory in the sender until the receiver has unpickled it; a buffer passed as a Process argument pins it until the Process object is released, because the child receives the file descriptors when it is spawned.

Two transports exist. multiprocessing (a Queue, a Pipe, Process arguments, or a Pool) pickles the descriptor, or a buffer, and duplicates the file descriptors into the receiving process; plain pickle cannot carry them and raises. A process with its own file descriptor passing sends fds, sizes, and size itself, and the receiver rebuilds the descriptor with from_fds().

Note

The sizes are controlled by the exporting peer. Receivers must treat them as untrusted and import only through Buffer.from_ipc_descriptor(), which checks what it can and fails instead of mapping a size the driver rejects.

Methods

__init__(*args, **kwargs)#
classmethod from_fds(
cls,
fds: Iterable[int | IPCAllocationHandle],
sizes: Iterable[int],
*,
size: int | None = None,
) → VirtualMemoryIPCBufferDescriptor#

Build a descriptor from POSIX file descriptors received outside multiprocessing.

The exporter sends fds, sizes, and size of its descriptor through a transport of its own (a Unix socket with SCM_RIGHTS, for example); the receiver rebuilds the descriptor here and imports it with Buffer.from_ipc_descriptor(). The result’s handle_type is "posix_fd", the only handle type a file descriptor can carry.

Parameters:
  • fds (Iterable[int | IPCAllocationHandle]) – One handle per physical allocation, in address order, as the exporter’s fds listed them. An int is duplicated: the caller keeps ownership of the original and closes it. An IPCAllocationHandle is shared and closes with its last holder.

  • sizes (Iterable[int]) – The exporter’s sizes, one per handle.

  • size (int, optional) – The exporter’s size, at most the sum of sizes; the sum by default.

Raises:

Attributes

fds#

tuple[int, …]

The exported file descriptors as integers, for a transport of your own.

They belong to this descriptor: send or duplicate them while it is alive, because each one is closed when the descriptor is released. Keep the descriptor in a variable while you use them; the numbers from buf.ipc_descriptor.fds alone may already be closed.

handle_type#

The handle type the exporter used; the importing resource must be configured with the same.

handles#

tuple[IPCAllocationHandle, …]

The exported handles, one IPCAllocationHandle per allocation, in address order.

The descriptor owns them and closes them when it is released.

size#

int

Type:

IPCBufferDescriptor.size

sizes#

tuple[int, …]

Size of each physical allocation, in address order; the sum is at least size.