Skip to content

Commit c012bff

Browse files
leofangclaude
andcommitted
Harden green context stream creation and resource queries
- Let the driver validate the nonblocking flag for green context streams: cuGreenCtxStreamCreate rejects CU_STREAM_DEFAULT. On failure, check if the context is green + nonblocking is False and raise a clear ValueError. - cuCtxGetStreamPriorityRange failure (CUDA_ERROR_INVALID_CONTEXT) now raises: "No current CUDA context. Call dev.set_current() before creating streams." - C++ create_stream_handle returns CUDA_ERROR_NOT_SUPPORTED if the context is green but cuGreenCtxStreamCreate is unavailable (CUDA < 12.5), instead of falling through to cuStreamCreateWithPriority. - ctx.resources.workqueue now dispatches to cuGreenCtxGetDevResource for green contexts, matching the SM query path. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent b6959e4 commit c012bff

4 files changed

Lines changed: 62 additions & 14 deletions

File tree

cuda_core/cuda/core/_cpp/resource_handles.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,11 @@ StreamHandle create_stream_handle(const ContextHandle& h_ctx, unsigned int flags
414414

415415
// Dispatch: green context uses cuGreenCtxStreamCreate, primary uses cuStreamCreateWithPriority
416416
GreenCtxHandle h_green = get_context_green_ctx(h_ctx);
417-
if (h_green && p_cuGreenCtxStreamCreate) {
417+
if (h_green) {
418+
if (!p_cuGreenCtxStreamCreate) {
419+
err = CUDA_ERROR_NOT_SUPPORTED;
420+
return {};
421+
}
418422
if (CUDA_SUCCESS != (err = p_cuGreenCtxStreamCreate(&stream, as_cu(h_green), flags, priority))) {
419423
return {};
420424
}

cuda_core/cuda/core/_device_resources.pyx

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -548,19 +548,35 @@ cdef class DeviceResources:
548548
cdef cydriver.CUdevResource _wq
549549

550550
IF CUDA_CORE_BUILD_MAJOR >= 13:
551+
cdef GreenCtxHandle h_green
551552
if self._h_context:
552-
# Context-level query
553-
with nogil:
554-
HANDLE_RETURN(cydriver.cuCtxGetDevResource(
555-
as_cu(self._h_context),
556-
&_wq_config,
557-
cydriver.CUdevResourceType.CU_DEV_RESOURCE_TYPE_WORKQUEUE_CONFIG,
558-
))
559-
HANDLE_RETURN(cydriver.cuCtxGetDevResource(
560-
as_cu(self._h_context),
561-
&_wq,
562-
cydriver.CUdevResourceType.CU_DEV_RESOURCE_TYPE_WORKQUEUE,
563-
))
553+
h_green = get_context_green_ctx(self._h_context)
554+
if h_green:
555+
# Green context query
556+
with nogil:
557+
HANDLE_RETURN(cydriver.cuGreenCtxGetDevResource(
558+
as_cu(h_green),
559+
&_wq_config,
560+
cydriver.CUdevResourceType.CU_DEV_RESOURCE_TYPE_WORKQUEUE_CONFIG,
561+
))
562+
HANDLE_RETURN(cydriver.cuGreenCtxGetDevResource(
563+
as_cu(h_green),
564+
&_wq,
565+
cydriver.CUdevResourceType.CU_DEV_RESOURCE_TYPE_WORKQUEUE,
566+
))
567+
else:
568+
# Primary context query
569+
with nogil:
570+
HANDLE_RETURN(cydriver.cuCtxGetDevResource(
571+
as_cu(self._h_context),
572+
&_wq_config,
573+
cydriver.CUdevResourceType.CU_DEV_RESOURCE_TYPE_WORKQUEUE_CONFIG,
574+
))
575+
HANDLE_RETURN(cydriver.cuCtxGetDevResource(
576+
as_cu(self._h_context),
577+
&_wq,
578+
cydriver.CUdevResourceType.CU_DEV_RESOURCE_TYPE_WORKQUEUE,
579+
))
564580
else:
565581
# Device-level query
566582
with nogil:

cuda_core/cuda/core/_stream.pyx

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ from cuda.core._resource_handles cimport (
3030
create_event_handle_noctx,
3131
create_stream_handle,
3232
create_stream_handle_with_owner,
33+
get_context_green_ctx,
3334
get_current_context,
35+
get_last_error,
3436
get_legacy_stream,
3537
get_per_thread_stream,
3638
get_stream_context,
@@ -143,8 +145,15 @@ cdef class Stream:
143145
else cydriver.CUstream_flags.CU_STREAM_DEFAULT)
144146
# TODO: we might want to consider memoizing high/low per CUDA context and avoid this call
145147
cdef int high, low
148+
cdef cydriver.CUresult res_code
146149
with nogil:
147-
HANDLE_RETURN(cydriver.cuCtxGetStreamPriorityRange(&high, &low))
150+
res_code = cydriver.cuCtxGetStreamPriorityRange(&high, &low)
151+
if res_code != cydriver.CUresult.CUDA_SUCCESS:
152+
if res_code == cydriver.CUresult.CUDA_ERROR_INVALID_CONTEXT:
153+
raise RuntimeError(
154+
"No current CUDA context. Call dev.set_current() before creating streams."
155+
)
156+
HANDLE_RETURN(res_code)
148157
cdef int prio
149158
if priority is not None:
150159
prio = priority
@@ -157,6 +166,18 @@ cdef class Stream:
157166
# For green contexts, the C++ layer auto-dispatches to cuGreenCtxStreamCreate.
158167
h_stream = create_stream_handle(h_context, flags, prio)
159168
if not h_stream:
169+
cdef bint is_green_ctx = h_context and get_context_green_ctx(h_context).get() != NULL
170+
if is_green_ctx and not nonblocking:
171+
raise ValueError(
172+
"Green context streams must be non-blocking. "
173+
"Use StreamOptions(nonblocking=True) or omit the option (True is the default)."
174+
)
175+
if is_green_ctx:
176+
HANDLE_RETURN(get_last_error())
177+
raise RuntimeError(
178+
"Failed to create green context stream. "
179+
"cuGreenCtxStreamCreate may not be available (requires CUDA 12.5+)."
180+
)
160181
raise RuntimeError("Failed to create CUDA stream")
161182
self = Stream._from_handle(cls, h_stream)
162183
self._nonblocking = int(nonblocking)

cuda_core/tests/test_green_context.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,13 @@ def test_create_stream_on_primary_raises(self, init_cuda):
293293
with pytest.raises(RuntimeError, match="only supported on green contexts"):
294294
ctx.create_stream()
295295

296+
def test_create_stream_blocking_raises(self, green_ctx):
297+
"""Green context streams must be non-blocking."""
298+
from cuda.core import StreamOptions
299+
300+
with pytest.raises(ValueError, match="must be non-blocking"):
301+
green_ctx.create_stream(StreamOptions(nonblocking=False))
302+
296303
def test_create_stream_explicit(self, green_ctx):
297304
"""Create a stream directly from the green context (no set_current)."""
298305
stream = green_ctx.create_stream()

0 commit comments

Comments
 (0)