SIGN IN SIGN UP

bindings/rust: add prepMemView/releaseMemView to the C API and nixl-sys (#2060)

Needed for the LPU backend: `prepMemView` resolves a registered buffer
into the
`nixlMemViewH` that the device-side send and receive calls take as input
on the
GPU. Without a Rust binding the backend cannot prepare its data-plane
views, so
the whole device data path is unreachable.

## What?

Binds `prepMemView` / `releaseMemView` into the Rust C API layer and
`nixl-sys`.

- C API: `prep_mem_view_local` / `_remote` / `release_mem_view`, plus
`create_remote_dlist` / `_add_desc` / `_destroy_remote_dlist`, with
matching
  `stubs.cpp` forwarders.
- nixl-sys: `Agent::prep_mem_view_local` / `_remote` returning a
`MemView` that
  releases on `Drop`, and `RemoteDescList` / `RemoteDescriptor` beside
  `RegDescList` / `XferDescList`.
- Four tests in `tests/mem_view.rs`: local and remote happy paths,
unknown
remote agent, all-null-agent list. Helpers shared with `tests.rs` live
in
  `tests/common/mod.rs`.

## Why?

The device API is GPU-initiated: `prepMemView` returns the
`nixlMemViewH` a
kernel passes to `nixlPut` or `nixlSend`. Its consumers so far have been
CUDA
C++, where host and device code share one program and a C boundary buys
nothing,
so it was never bound. It is needed once Rust owns the agent and view
lifecycle
while a thin CUDA shim launches the kernels.

## How?

**The remote overload binds `nixl_remote_dlist_t`, not a single agent
name.** A
view can span peers: `nixl_ep` puts several agents in one list, using
`nixl_null_agent` for unaddressed ranks so descriptor indices stay
aligned with
rank numbers (`examples/device/ep/csrc/nixl_ep.cpp:1328-1333`).

**`prep_mem_view_*` are `unsafe`.** A view holds the registration
handles of its
buffers and is stored for the lifetime of the endpoint alongside them,
so a
lifetime bound would make the owning struct self-referential.
`RemoteDescList`
carries no lifetime: `nixl_capi_remote_dlist_add_desc` constructs a
`nixlRemoteDesc` by value with a `std::string` agent name and
`nixlDescList`
stores `std::vector<T>`, so nothing borrows once the call returns.

**The tests are gated on a CUDA toolkit.** They allocate VRAM, so
`build.rs`
probes `CUDA_PATH`, `CUDA_HOME`, then `/usr/local/cuda` in turn, and
compiles
them only if it finds one; a build without CUDA links no CUDA symbols.
With a
toolkit but no device they skip at run time.

**`test_prep_mem_view_remote` is opt-in behind
`NIXL_TEST_DEVICE_LANE=1`.** It is
the only one needing a device-capable RDMA lane, which UCX offers only
over
accelerated IB; without one it fails at `ucp_device.c: lane not found
for
element 0`, which no up-front check can predict. Gating it rather than
skipping
on failure keeps a real regression a failure.

## Testing

104 tests pass on `cargo test` — 96 in `tests.rs`, 4 in `mem_view.rs`, 4
in
`test_sync_manager.rs` — on UCX 1.21 with a CUDA device, against
`libnixl` built
from this branch's base. Three of the four memory-view tests exercise
the path by
default; the fourth was confirmed to run and pass with
`NIXL_TEST_DEVICE_LANE=1`.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
  * Added Rust support for preparing local and remote memory views.
* Added remote buffer descriptors, descriptor lists, and memory-view
lifecycle management.
  * Added CUDA toolkit detection for GPU-enabled builds.

* **Bug Fixes**
* Improved error handling for invalid memory-view and remote descriptor
operations.

* **Tests**
  * Added CUDA-based local and remote memory-view integration tests.
* Documented CUDA, RDMA, and NIXL test prerequisites and opt-in
behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Shahaf Kiselnik <smeir@nvidia.com>
S
ShahafMeir committed
6d855fc135f8c56340a078751769f92f74cf57ee
Parent: e1cbabc
Committed by GitHub <noreply@github.com> on 8/18/2026, 12:51:17 PM