@@ -216,8 +216,9 @@ cdef class Stream:
216216 return as_intptr(self ._h_stream) == as_intptr((< Stream> other)._h_stream)
217217
218218 def __repr__ (self ) -> str:
219- Stream_ensure_ctx(self )
220- return f"<Stream handle = {as_intptr(self ._h_stream):# x} context={as_intptr(self._h_context):#x}>"
219+ cdef ContextHandle h_context
220+ Stream_get_ctx(self , &h_context )
221+ return f"<Stream handle = {as_intptr(self ._h_stream):# x} context={as_intptr(h_context):#x}>"
221222
222223 @property
223224 def handle (self ) -> cuda.bindings.driver.CUstream:
@@ -277,9 +278,11 @@ cdef class Stream:
277278 # Create an Event object (or reusing the given one ) by recording
278279 # on the stream. Event flags such as disabling timing , nonblocking ,
279280 # and CU_EVENT_RECORD_EXTERNAL , can be set in EventOptions.
281+ cdef ContextHandle h_context
282+ cdef int device_id
280283 if event is None:
281- Stream_ensure_ctx_device (self )
282- event = cyEvent._init(cyEvent, self ._device_id, self ._h_context , options, False )
284+ Stream_get_ctx_device (self , & h_context , & device_id )
285+ event = cyEvent._init(cyEvent, device_id, h_context , options, False )
283286 elif event.is_ipc_enabled:
284287 raise TypeError(
285288 "IPC-enabled events should not be re-recorded , instead create a "
@@ -350,15 +353,27 @@ cdef class Stream:
350353
351354 """
352355 from cuda.core._device import Device # avoid circular import
353- Stream_ensure_ctx_device(self )
354- return Device(self._device_id )
356+ cdef ContextHandle h_context
357+ cdef int device_id
358+ Stream_get_ctx_device(self , &h_context , &device_id )
359+ return Device(device_id )
355360
356361 @property
357362 def context(self ) -> Context:
358- """Return the :obj:`~_context.Context` associated with this stream."""
359- Stream_ensure_ctx(self )
360- Stream_ensure_ctx_device(self )
361- return Context._from_handle(Context , self._h_context , self._device_id )
363+ """Return the :obj:`~_context.Context` associated with this stream.
364+
365+ Note
366+ ----
367+ A default stream (:obj:`LEGACY_DEFAULT_STREAM` or
368+ :obj:`PER_THREAD_DEFAULT_STREAM`) carries no context of its own; it
369+ refers to whichever context is current , so this returns the current
370+ context at call time.
371+
372+ """
373+ cdef ContextHandle h_context
374+ cdef int device_id
375+ Stream_get_ctx_device(self , &h_context , &device_id )
376+ return Context._from_handle(Context , h_context , device_id )
362377
363378 @property
364379 def resources(self ) -> DeviceResources:
@@ -368,9 +383,10 @@ cdef class Stream:
368383 that context was provisioned with. For streams on the primary
369384 context , returns the full device resources.
370385 """
371- Stream_ensure_ctx(self )
372- Stream_ensure_ctx_device(self )
373- return DeviceResources._init_from_ctx(self._h_context , self._device_id )
386+ cdef ContextHandle h_context
387+ cdef int device_id
388+ Stream_get_ctx_device(self , &h_context , &device_id )
389+ return DeviceResources._init_from_ctx(h_context , device_id )
374390
375391 @staticmethod
376392 def from_handle(handle ) -> Stream:
@@ -447,39 +463,61 @@ cpdef Stream default_stream():
447463 return LEGACY_DEFAULT_STREAM
448464
449465
450- cdef inline int Stream_ensure_ctx(Stream self ) except ?- 1 nogil:
451- """ Ensure the stream's context handle is populated."""
466+ cdef inline bint Stream_is_default_token(Stream self ) noexcept nogil:
467+ """ Return True for CU_STREAM_LEGACY and CU_STREAM_PER_THREAD.
468+
469+ These tokens carry no context of their own; they refer to whatever context
470+ is current, so nothing resolved from one may be cached on the object.
471+ """
472+ cdef uintptr_t h = < uintptr_t> as_cu(self ._h_stream)
473+ return h == < uintptr_t> cydriver.CU_STREAM_LEGACY or h == < uintptr_t> cydriver.CU_STREAM_PER_THREAD
474+
475+
476+ cdef inline int Stream_get_ctx(Stream self , ContextHandle* h_context) except ?- 1 nogil:
477+ """ Resolve the stream's context handle into ``h_context``."""
452478 cdef cydriver.CUcontext ctx
453- if not self ._h_context:
454- self ._h_context = get_stream_context( self ._h_stream)
479+ cdef bint is_default = Stream_is_default_token( self )
480+
455481 if self ._h_context:
482+ h_context[0 ] = self ._h_context
456483 return 0
457- HANDLE_RETURN(cydriver.cuStreamGetCtx(as_cu(self ._h_stream), & ctx))
458- if ctx != NULL :
459- with gil:
460- self ._h_context = create_context_handle_ref(ctx)
484+
485+ h_context[0 ] = get_stream_context(self ._h_stream)
486+ if not h_context[0 ]:
487+ HANDLE_RETURN(cydriver.cuStreamGetCtx(as_cu(self ._h_stream), & ctx))
488+ if ctx != NULL :
489+ with gil:
490+ h_context[0 ] = create_context_handle_ref(ctx)
491+
492+ if h_context[0 ] and not is_default:
493+ self ._h_context = h_context[0 ]
461494 return 0
462495
463496
464- cdef inline int Stream_ensure_ctx_device (Stream self ) except ?- 1 :
465- """ Ensure the stream's context and device_id are populated ."""
497+ cdef inline int Stream_get_ctx_device (Stream self , ContextHandle * h_context, int * device_id ) except ?- 1 :
498+ """ Resolve the stream's context handle and device ID ."""
466499 cdef cydriver.CUcontext ctx
467500 cdef cydriver.CUdevice target_dev
468501 cdef ContextHandle current_context
469502 cdef bint switch_context
503+ cdef bint is_default = Stream_is_default_token(self )
470504
471- if self ._device_id < 0 :
472- with nogil:
505+ with nogil:
506+ Stream_get_ctx(self , h_context)
507+ if self ._device_id >= 0 and not is_default:
508+ device_id[0 ] = self ._device_id
509+ else :
473510 # Get device ID from context, switching context temporarily if needed
474- Stream_ensure_ctx(self )
475511 current_context = get_current_context()
476- switch_context = (as_cu(current_context) != as_cu(self ._h_context ))
512+ switch_context = (as_cu(current_context) != as_cu(h_context[ 0 ] ))
477513 if switch_context:
478- HANDLE_RETURN(cydriver.cuCtxPushCurrent(as_cu(self ._h_context )))
514+ HANDLE_RETURN(cydriver.cuCtxPushCurrent(as_cu(h_context[ 0 ] )))
479515 HANDLE_RETURN(cydriver.cuCtxGetDevice(& target_dev))
480516 if switch_context:
481517 HANDLE_RETURN(cydriver.cuCtxPopCurrent(& ctx))
482- self ._device_id = < int > target_dev
518+ device_id[0 ] = < int > target_dev
519+ if not is_default:
520+ self ._device_id = device_id[0 ]
483521 return 0
484522
485523
0 commit comments