From 2a33c033dcf08fd993ae7bd10101c3020430ce16 Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Tue, 27 Oct 2026 13:34:49 +0200 Subject: [PATCH] cuda.core: treat the NULL stream as a default-stream token Stream_is_default_token matched only CU_STREAM_LEGACY and CU_STREAM_PER_THREAD, so a Stream over handle 0, such as Stream.from_handle(0), still cached the first context and device it resolved. The driver resolves handle 0 against the current context like the other two, so after a context switch .context, .device, .resources and record() kept naming the old context. Closes #3242 Signed-off-by: Vyron Vasileiadis --- cuda_core/cuda/core/_stream.pyx | 5 +++-- cuda_core/docs/source/release/1.3.0-notes.rst | 7 +++++++ cuda_core/tests/test_green_context.py | 12 ++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/cuda_core/cuda/core/_stream.pyx b/cuda_core/cuda/core/_stream.pyx index 1876885e0cf..f2bdf67c138 100644 --- a/cuda_core/cuda/core/_stream.pyx +++ b/cuda_core/cuda/core/_stream.pyx @@ -522,13 +522,14 @@ cdef inline bint Stream_handle_is_default_token(cydriver.CUstream s) noexcept no These tokens carry no context of their own; they refer to whatever context is current, so nothing resolved from one may be cached on the object. + The NULL stream (handle 0) is such a token too. """ cdef uintptr_t h = s - return h == cydriver.CU_STREAM_LEGACY or h == cydriver.CU_STREAM_PER_THREAD + return h == 0 or h == cydriver.CU_STREAM_LEGACY or h == cydriver.CU_STREAM_PER_THREAD cdef inline bint Stream_is_default_token(Stream self) noexcept nogil: - """Return True when this stream is CU_STREAM_LEGACY or CU_STREAM_PER_THREAD.""" + """Return True when this stream is the NULL stream, CU_STREAM_LEGACY or CU_STREAM_PER_THREAD.""" return Stream_handle_is_default_token(as_cu(self._h_stream)) diff --git a/cuda_core/docs/source/release/1.3.0-notes.rst b/cuda_core/docs/source/release/1.3.0-notes.rst index f63ce1f1cff..c092e159bac 100644 --- a/cuda_core/docs/source/release/1.3.0-notes.rst +++ b/cuda_core/docs/source/release/1.3.0-notes.rst @@ -321,6 +321,13 @@ Fixes and enhancements ``repr`` now shows ``U`` for unified operands. (`#2649 `__) +- A :class:`Stream` over the NULL stream (handle 0), such as + ``Stream.from_handle(0)``, no longer caches the first context and device it + observes. Like ``LEGACY_DEFAULT_STREAM`` and ``PER_THREAD_DEFAULT_STREAM`` + since 1.2.0, it now resolves ``Stream.context``, ``Stream.device``, + ``Stream.resources`` and ``Stream.record()`` against the current context. + (`#3242 `__) + Deprecations ------------ diff --git a/cuda_core/tests/test_green_context.py b/cuda_core/tests/test_green_context.py index a51e8e0bc2b..af2794721eb 100644 --- a/cuda_core/tests/test_green_context.py +++ b/cuda_core/tests/test_green_context.py @@ -15,6 +15,7 @@ ProgramOptions, SMResource, SMResourceOptions, + Stream, WorkqueueResource, WorkqueueResourceOptions, launch, @@ -560,6 +561,17 @@ def test_stream_and_event_track_green_context(self, green_ctx): stream.sync() event.sync() + @pytest.mark.agent_authored(model="claude-opus-5-5") + def test_null_stream_follows_current_context(self, init_cuda, green_ctx): + stream = Stream.from_handle(0) + assert stream.context == init_cuda.context + + with use_context(init_cuda, green_ctx): + assert stream.context == green_ctx + assert stream.record().context == green_ctx + + assert stream.context == init_cuda.context + @pytest.mark.agent_authored(model="gpt-5.6") def test_device_receiver_targets_stored_green_context(self, init_cuda, green_ctx): primary_ctx = init_cuda.context