Skip to content

cuda.core: return CUresult from C++ handle factories instead of thread-local error state #2760

Description

@Andy-Jost

Summary

The C++ handle layer (cuda_core/cuda/core/_cpp/resource_handles.*) uses two status conventions. Factories return the handle and stash the CUresult in thread-local err, read back with get_last_error(). Functions that do not produce a handle (context_synchronize, context_get_device, graph_node_set_params, the graph_*_attachment family, deviceptr_alloc_raw, ...) return the CUresult directly with results in out-parameters, like the driver API. Proposal: use the second convention everywhere and remove the thread-local error state.

Why

The documented justification for thread-local err is that factories can be called from nogil code without acquiring the GIL on the success path. HANDLE_RETURN is itself nogil and only takes the GIL on a non-success status, so a CUresult-returning factory has the same property. What is left is expression-style ergonomics (h = create_stream_handle(...)), which would only pay off with a real exception channel, and this layer cannot have one.

Unifying on direct CUresult returns would:

  • Remove the read-before-clobber footgun and the get_last_error / peek_last_error / clear_last_error trio.
  • Remove an ambiguity that exists today: an empty handle can mean a legitimate "none" (get_current_context() with no current context, get_context_green_ctx() on a plain context) or a failure, and only err tells them apart. With CUresult f(Handle* out, ...), success plus an empty out-handle is unambiguous.
  • Make internal composition explicit propagation instead of "the callee already set err, return an empty handle".
  • Give secondary statuses a natural home as out-parameters (graph_node_set_params already does this with restore_status).

Proposed rule

Anything that can fail returns CUresult and delivers its result through an out-parameter, mirroring the driver. Accessors that cannot fail (get_stream_context, get_event_device_id, the *_ref constructors, ...) keep returning values directly. One rule, no exceptions keyed on return type.

Cython call sites become:

cdef StreamHandle h
HANDLE_RETURN(create_stream_handle(&h, h_ctx, flags, priority))

Scope

Rough counts on the current tree: 66 handle-returning factory signatures, 37 internal err = assignments in the C++ layer, and 21 Cython sites in 13 modules that read err, plus every Cython factory call. Mechanical and behavior-neutral, but it touches every module, so it should land as a standalone change with no functional edits mixed in, after #2750 and #2759 merge. It is independent of the planned follow-up on calling raw driver function pointers instead of the Cython wrappers.

Non-goals

Refs: #2758 (error-handling policy RFC), #2759 (implementation), review discussion on _cpp/DESIGN.md in #2759.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P1Medium priority - Should docuda.coreEverything related to the cuda.core moduleenhancementAny code-related improvements

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions