@@ -17,12 +17,14 @@ from cuda.core._resource_handles cimport (
1717 DevicePtrHandle,
1818 StreamHandle,
1919 deviceptr_create_with_owner,
20+ deviceptr_create_with_mr,
21+ register_mr_dealloc_callback,
2022 as_intptr,
2123 as_cu,
2224 set_deallocation_stream,
2325)
2426
25- from cuda.core._stream cimport Stream_accept, Stream
27+ from cuda.core._stream cimport Stream, Stream_accept
2628from cuda.core._utils.cuda_utils cimport HANDLE_RETURN
2729
2830import sys
@@ -37,6 +39,30 @@ from cuda.core._dlpack import DLDeviceType, make_py_capsule
3739from cuda.core._utils.cuda_utils import driver
3840from cuda.core._device import Device
3941
42+
43+ # =============================================================================
44+ # MR deallocation callback (invoked from C++ shared_ptr deleter)
45+ # =============================================================================
46+
47+ cdef void _mr_dealloc_callback(
48+ object mr,
49+ cydriver.CUdeviceptr ptr,
50+ size_t size,
51+ const StreamHandle& h_stream,
52+ ) noexcept:
53+ """ Called by the C++ deleter to deallocate via MemoryResource.deallocate."""
54+ try :
55+ stream = None
56+ if h_stream:
57+ stream = Stream._from_handle(Stream, h_stream)
58+ mr.deallocate(int (ptr), size, stream)
59+ except Exception as exc:
60+ print (f" Warning: mr.deallocate() failed during Buffer destruction: {exc}" ,
61+ file = sys.stderr)
62+
63+ register_mr_dealloc_callback(_mr_dealloc_callback)
64+
65+
4066__all__ = [' Buffer' , ' MemoryResource' ]
4167
4268
@@ -73,27 +99,30 @@ cdef class Buffer:
7399 @classmethod
74100 def _init (
75101 cls , ptr: DevicePointerT , size_t size , mr: MemoryResource | None = None ,
76- stream: Stream | None = None , ipc_descriptor: IPCBufferDescriptor | None = None ,
102+ ipc_descriptor: IPCBufferDescriptor | None = None ,
77103 owner : object | None = None
78104 ):
79- """ Legacy init for compatibility - creates a non-owning ref handle .
105+ """ Create a Buffer from a raw pointer .
80106
81- Note: The stream parameter is accepted for API compatibility but is
82- ignored since non-owning refs are never freed by the handle.
107+ When ``mr`` is provided, the buffer takes ownership: ``mr.deallocate()``
108+ is called when the buffer is closed or garbage collected. When ``owner``
109+ is provided, the owner is kept alive but no deallocation is performed.
83110 """
84111 if mr is not None and owner is not None :
85112 raise ValueError (" owner and memory resource cannot be both specified together" )
86113 cdef Buffer self = Buffer.__new__ (cls )
87- self ._h_ptr = deviceptr_create_with_owner(< uintptr_t> (int (ptr)), owner)
114+ cdef uintptr_t c_ptr = < uintptr_t> (int (ptr))
115+ if mr is not None :
116+ self ._h_ptr = deviceptr_create_with_mr(c_ptr, size, mr)
117+ else :
118+ self ._h_ptr = deviceptr_create_with_owner(c_ptr, owner)
88119 self ._size = size
89120 self ._memory_resource = mr
90121 self ._ipc_data = IPCDataForBuffer(ipc_descriptor, True ) if ipc_descriptor is not None else None
91122 self ._owner = owner
92123 self ._mem_attrs_inited = False
93124 return self
94125
95- # No __dealloc__ needed - RAII handles cleanup via _h_ptr destructor
96-
97126 def __reduce__ (self ):
98127 # Must not serialize the parent's stream!
99128 return Buffer.from_ipc_descriptor, (self .memory_resource, self .get_ipc_descriptor())
@@ -112,16 +141,19 @@ cdef class Buffer:
112141 size : int
113142 Memory size of the buffer
114143 mr : :obj:`~_memory.MemoryResource`, optional
115- Memory resource associated with the buffer
144+ Memory resource associated with the buffer. When provided ,
145+ :meth:`MemoryResource.deallocate` is called when the buffer is
146+ closed or garbage collected.
116147 owner : object , optional
117148 An object holding external allocation that the ``ptr`` points to.
118149 The reference is kept as long as the buffer is alive.
119150 The ``owner`` and ``mr`` cannot be specified together.
120151
121152 Note
122153 ----
123- This creates a non-owning reference. The pointer will NOT be freed
124- when the Buffer is closed or garbage collected.
154+ When neither ``mr`` nor ``owner`` is specified , this creates a
155+ non-owning reference. The pointer will NOT be freed when the
156+ :class:`Buffer` is closed or garbage collected.
125157 """
126158 return Buffer._init(ptr , size , mr = mr, owner = owner)
127159
0 commit comments