Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion cuda_core/cuda/core/_linker.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,27 @@
#
# SPDX-License-Identifier: Apache-2.0

from libcpp.vector cimport vector

from cuda.bindings cimport cydriver

from ._resource_handles cimport NvJitLinkHandle, CuLinkHandle


cdef class Linker:
cdef:
NvJitLinkHandle _nvjitlink_handle
CuLinkHandle _culink_handle
# _drv_jit_keys/_drv_jit_values are the C arrays handed to cuLinkCreate.
# The driver retains a reference to the optionValues array for the life
# of the CUlinkState (it writes back log-size outputs into its slots),
# so these must live past cuLinkCreate and outlive cuLinkDestroy.
# Declared after _culink_handle so their C++ destructors run AFTER
# cuLinkDestroy executes during tp_dealloc.
Copy link
Copy Markdown
Collaborator

@rparolin rparolin Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its easy to miss the subtly here that reordering the fields breaks the assumptions of object lifetimes and can cause memory issues. Since I don't have any better ideas on how to guard against this... I'd make it VERY obvious that people should not be reordering the members here unless they know what they are doing. Something to the effect...

# WARNING: Here be dragons... do not reorder data members... <reasons>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

python
def close(self):
    if self._culink_handle is not None:
        cuLinkDestroy(self._culink_handle)
        self._culink_handle = None
    self._drv_jit_keys.clear()
    self._drv_jit_values.clear()

def __dealloc__(self):
    self.close()  # ensures correct order even without 'with' block

I'm not convinced this is much better... but I offer it as food for thought. We could specify the correct destruction order of the members instead in a member function and manually called that when the object is destroyed by the GC. The best I can say about this is it less subtle that we are attempting to handle complext lifetime issues.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vector[cydriver.CUjit_option] _drv_jit_keys
vector[void*] _drv_jit_values
bint _use_nvjitlink
object _drv_log_bufs # formatted_options list (driver); None for nvjitlink; cleared in link()
object _drv_log_bufs # formatted_options list (driver); None for nvjitlink
str _info_log # decoded log; None until link() or pre-link get_*_log()
str _error_log # decoded log; None until link() or pre-link get_*_log()
object _options # LinkerOptions
Expand Down
Loading
Loading