@@ -4,10 +4,7 @@ cimport cython
44from cpython.object cimport PyObject
55from cpython.pyport cimport PY_SSIZE_T_MAX
66from cpython.slice cimport PySlice_GetIndicesEx
7- from cpython.weakref cimport (
8- PyWeakref_GetObject,
9- PyWeakref_NewRef,
10- )
7+ from cpython.weakref cimport PyWeakref_NewRef
118from cython cimport Py_ssize_t
129
1310import numpy as np
@@ -29,6 +26,14 @@ from pandas._libs.util cimport (
2926 is_integer_object,
3027)
3128
29+ include " free_threading_config.pxi"
30+
31+ IF CYTHON_COMPATIBLE_WITH_FREE_THREADING:
32+ from cpython.ref cimport Py_DECREF
33+ from cpython.weakref cimport PyWeakref_GetRef
34+ ELSE :
35+ from cpython.weakref cimport PyWeakref_GetObject
36+
3237
3338cdef extern from " Python.h" :
3439 PyObject* Py_None
@@ -908,17 +913,37 @@ cdef class BlockValuesRefs:
908913 # if force=False. Clearing for every insertion causes slowdowns if
909914 # all these objects stay alive, e.g. df.items() for wide DataFrames
910915 # see GH#55245 and GH#55008
916+ IF CYTHON_COMPATIBLE_WITH_FREE_THREADING:
917+ cdef PyObject* pobj
918+ cdef bint status
919+
911920 if force or len (self .referenced_blocks) > self .clear_counter:
912- self .referenced_blocks = [
913- ref for ref in self .referenced_blocks
914- if PyWeakref_GetObject(ref) != Py_None
915- ]
921+ IF CYTHON_COMPATIBLE_WITH_FREE_THREADING:
922+ new_referenced_blocks = []
923+ for ref in self .referenced_blocks:
924+ status = PyWeakref_GetRef(ref, & pobj)
925+ if status == - 1 :
926+ return
927+ elif status == 1 :
928+ new_referenced_blocks.append(ref)
929+ Py_DECREF(< object > pobj)
930+ self .referenced_blocks = new_referenced_blocks
931+ ELSE :
932+ self .referenced_blocks = [
933+ ref for ref in self .referenced_blocks
934+ if PyWeakref_GetObject(ref) != Py_None
935+ ]
936+
916937 nr_of_refs = len (self .referenced_blocks)
917938 if nr_of_refs < self .clear_counter // 2 :
918939 self .clear_counter = max (self .clear_counter // 2 , 500 )
919940 elif nr_of_refs > self .clear_counter:
920941 self .clear_counter = max (self .clear_counter * 2 , nr_of_refs)
921942
943+ cpdef _add_reference_maybe_locked(self , Block blk):
944+ self ._clear_dead_references()
945+ self .referenced_blocks.append(PyWeakref_NewRef(blk, None ))
946+
922947 cpdef add_reference(self , Block blk):
923948 """ Adds a new reference to our reference collection.
924949
@@ -927,8 +952,15 @@ cdef class BlockValuesRefs:
927952 blk : Block
928953 The block that the new references should point to.
929954 """
955+ IF CYTHON_COMPATIBLE_WITH_FREE_THREADING:
956+ with cython.critical_section(self ):
957+ self ._add_reference_maybe_locked(blk)
958+ ELSE :
959+ self ._add_reference_maybe_locked(blk)
960+
961+ def _add_index_reference_maybe_locked (self , index: object ) -> None:
930962 self._clear_dead_references()
931- self .referenced_blocks.append(PyWeakref_NewRef(blk , None ))
963+ self.referenced_blocks.append(PyWeakref_NewRef(index , None ))
932964
933965 def add_index_reference(self , index: object ) -> None:
934966 """Adds a new reference to our reference collection when creating an index.
@@ -938,8 +970,16 @@ cdef class BlockValuesRefs:
938970 index : Index
939971 The index that the new reference should point to.
940972 """
941- self._clear_dead_references()
942- self.referenced_blocks.append(PyWeakref_NewRef(index , None ))
973+ IF CYTHON_COMPATIBLE_WITH_FREE_THREADING:
974+ with cython.critical_section(self ):
975+ self ._add_index_reference_maybe_locked(index)
976+ ELSE :
977+ self ._add_index_reference_maybe_locked(index)
978+
979+ def _has_reference_maybe_locked (self ) -> bool:
980+ self._clear_dead_references(force = True )
981+ # Checking for more references than block pointing to itself
982+ return len(self.referenced_blocks ) > 1
943983
944984 def has_reference(self ) -> bool:
945985 """Checks if block has foreign references.
@@ -951,6 +991,8 @@ cdef class BlockValuesRefs:
951991 -------
952992 bool
953993 """
954- self._clear_dead_references(force = True )
955- # Checking for more references than block pointing to itself
956- return len(self.referenced_blocks ) > 1
994+ IF CYTHON_COMPATIBLE_WITH_FREE_THREADING:
995+ with cython.critical_section(self ):
996+ return self ._has_reference_maybe_locked()
997+ ELSE :
998+ return self ._has_reference_maybe_locked()
0 commit comments