@@ -247,6 +247,33 @@ static void regionmetadata_inc_osc(Py_region_ptr_t self_ptr)
247247#define regionmetadata_inc_osc (self ) \
248248 (regionmetadata_inc_osc(REGION_PTR_CAST(self)))
249249
250+ /// This function checks the internal state, meaning the LRC, OSC and dirty
251+ /// status, to determine if the region should be closed. If possible, it will
252+ /// close the region and propagate the state to any parent region or cowns.
253+ ///
254+ /// Returns `0` on success. An error might come from closing the region
255+ /// see `regionmetadata_close` for potential errors.
256+ static int regionmetadata_check_for_close (regionmetadata * self ) {
257+ // If the region is marked as dirty, we can't trust the LRC or OSC
258+ // to update the status. The region has to be cleaned before it can
259+ // be closed
260+ if (regionmetadata_is_dirty (self )) {
261+ return 0 ;
262+ }
263+
264+ // The region has to remain open, if there are open subregions
265+ if (self -> osc != 0 ) {
266+ return 0 ;
267+ }
268+
269+ // The region has to remain open, if there are references into the region.
270+ if (self -> osc != 0 ) {
271+ return 0 ;
272+ }
273+
274+ return regionmetadata_close (self );
275+ }
276+
250277/// Decrements the OSC of the region. This might close the region if the LRC
251278/// and ORC both hit zero and the region is not marked as dirty.
252279///
@@ -262,11 +289,7 @@ static int regionmetadata_dec_osc(Py_region_ptr_t self_ptr)
262289 self -> osc -= 1 ;
263290
264291 // Check if the OSC decrease has closed this region as well.
265- if (self -> osc == 0 && self -> lrc == 0 && !regionmetadata_is_dirty (self )) {
266- return regionmetadata_close (self );
267- }
268-
269- return 0 ;
292+ return regionmetadata_check_for_close (self );
270293}
271294#define regionmetadata_dec_osc (self ) \
272295 (regionmetadata_dec_osc(REGION_PTR_CAST(self)))
@@ -316,6 +339,31 @@ static int regionmetadata_dec_rc(Py_region_ptr_t self_ptr)
316339#define regionmetadata_dec_rc (self ) \
317340 (regionmetadata_dec_rc(REGION_PTR_CAST(self)))
318341
342+ static void regionmetadata_inc_lrc (regionmetadata * self )
343+ {
344+ assert (HAS_METADATA (self ));
345+
346+ self -> lrc += 1 ;
347+ regionmetadata_open (self );
348+ }
349+ #define regionmetadata_inc_lrc (self ) \
350+ (regionmetadata_inc_lrc(REGION_DATA_CAST(self)))
351+
352+ /// Decrements the LRC of the region. This might close the region if the LRC
353+ /// and ORC both hit zero and the region is not marked as dirty.
354+ ///
355+ /// Returns `0` on success. An error might come from closing the region
356+ /// see `regionmetadata_close` for potential errors.
357+ static int regionmetadata_dec_lrc (regionmetadata * self )
358+ {
359+ assert (HAS_METADATA (self ));
360+
361+ self -> lrc -= 1 ;
362+ return regionmetadata_check_for_close (self );
363+ }
364+ #define regionmetadata_dec_lrc (self ) \
365+ (regionmetadata_dec_lrc(REGION_DATA_CAST(self)))
366+
319367static void regionmetadata_set_parent (regionmetadata * self , regionmetadata * parent ) {
320368 // Just a sanity check, since these cases should never happen
321369 assert (HAS_METADATA (self ) && "Can't set the parent on the immutable and local region" );
@@ -1928,7 +1976,7 @@ bool _Py_RegionAddReference(PyObject *src, PyObject *tgt) {
19281976 if (_Py_IsLocal (src )) {
19291977 // Record the borrowed reference in the LRC of the target region
19301978 // _Py_VPYDBG("Added borrowed ref %p --> %p (owner: '%s')\n", tgt, new_ref, get_region_name(tgt));
1931- Py_REGION_DATA (tgt )-> lrc += 1 ;
1979+ regionmetadata_inc_lrc ( Py_REGION_DATA (tgt )) ;
19321980 return true;
19331981 }
19341982
@@ -1991,9 +2039,8 @@ void _Py_RegionRemoveReference(PyObject *src, PyObject *tgt) {
19912039 regionmetadata * tgt_md = Py_REGION_DATA (tgt );
19922040 if (_Py_IsLocal (src )) {
19932041 // Dec LRC of the previously referenced region
1994- // TODO should this decrement be a function, if it hits zero,
1995- // then a region could become unreachable.
1996- tgt_md -> lrc -= 1 ;
2042+ // TODO should errors be propagated?
2043+ regionmetadata_dec_lrc (tgt_md );
19972044 return ;
19982045 }
19992046
0 commit comments