44
55use crate :: common:: linked_list:: LinkedList ;
66use crate :: common:: lock:: { PyMutex , PyRwLock } ;
7- use crate :: object:: { GC_NO_OWNER , GC_PERMANENT , GC_UNTRACKED , GcLink } ;
7+ use crate :: object:: { GC_NO_OWNER , GC_PERMANENT , GC_UNTRACKED , GcLink , GcOwner } ;
88use crate :: { AsObject , PyObject , PyObjectRef } ;
99use core:: ptr:: NonNull ;
10- use core:: sync:: atomic:: { AtomicBool , AtomicU32 , AtomicUsize , Ordering } ;
10+ use core:: sync:: atomic:: { AtomicBool , AtomicU16 , AtomicU32 , AtomicUsize , Ordering } ;
1111use std:: collections:: HashSet ;
1212
1313fn elapsed_secs (
@@ -143,7 +143,7 @@ fn release_count(count: &AtomicUsize) {
143143///
144144/// Objects with no owner — everything the shared context allocates, and anything
145145/// allocated with no interpreter current — belong to all of them.
146- fn is_owned_by ( obj : & PyObject , owner : u32 ) -> bool {
146+ fn is_owned_by ( obj : & PyObject , owner : GcOwner ) -> bool {
147147 let obj_owner = obj. gc_owner ( ) ;
148148 obj_owner == owner || obj_owner == GC_NO_OWNER
149149}
@@ -262,11 +262,11 @@ pub struct GcState {
262262 /// Allocation counter for gen0
263263 alloc_count : AtomicUsize ,
264264 /// Next `gc_owner` tag to hand to an interpreter.
265- next_owner : AtomicU32 ,
265+ next_owner : AtomicU16 ,
266266 /// Tags of interpreters that are gone. Their objects outlived them, so a
267267 /// collection adopts them — tags them `GC_NO_OWNER` again — as it walks,
268268 /// rather than leaving them for a collector that will never come.
269- retired : PyMutex < Vec < u32 > > ,
269+ retired : PyMutex < Vec < GcOwner > > ,
270270}
271271
272272// SAFETY: All fields are either inherently Send/Sync (atomics, RwLock, Mutex) or protected by PyMutex.
@@ -300,15 +300,15 @@ impl GcState {
300300 permanent_count : AtomicUsize :: new ( 0 ) ,
301301 collecting : PyMutex :: new ( ( ) ) ,
302302 alloc_count : AtomicUsize :: new ( 0 ) ,
303- next_owner : AtomicU32 :: new ( GC_NO_OWNER + 1 ) ,
303+ next_owner : AtomicU16 :: new ( GC_NO_OWNER + 1 ) ,
304304 retired : PyMutex :: new ( Vec :: new ( ) ) ,
305305 }
306306 }
307307
308308 /// Reserve a tag for a new interpreter. Tags are never reused; exhausting
309309 /// the 32-bit space falls back to `GC_NO_OWNER`, which costs isolation but
310310 /// stays correct, rather than aliasing a live interpreter.
311- fn alloc_owner ( & self ) -> u32 {
311+ fn alloc_owner ( & self ) -> GcOwner {
312312 self . next_owner
313313 . fetch_update ( Ordering :: Relaxed , Ordering :: Relaxed , |next| {
314314 next. checked_add ( 1 )
@@ -320,7 +320,7 @@ impl GcState {
320320 /// whatever it left behind. Retagging the objects here would mean walking
321321 /// every list under an interpreter drop, which happens while a collection
322322 /// holds the collecting lock.
323- fn retire_owner ( & self , owner : u32 ) {
323+ fn retire_owner ( & self , owner : GcOwner ) {
324324 if owner == GC_NO_OWNER {
325325 return ;
326326 }
@@ -343,7 +343,7 @@ impl GcState {
343343 ///
344344 /// # Safety
345345 /// obj must be a valid pointer to a PyObject
346- pub unsafe fn track_object ( & self , obj : NonNull < PyObject > , owner : u32 ) {
346+ pub unsafe fn track_object ( & self , obj : NonNull < PyObject > , owner : GcOwner ) {
347347 let obj_ref = unsafe { obj. as_ref ( ) } ;
348348 obj_ref. set_gc_tracked ( ) ;
349349 obj_ref. set_gc_generation ( 0 ) ;
@@ -407,10 +407,10 @@ impl GcState {
407407 /// interpreter owns.
408408 /// If generation is None, returns all such objects.
409409 /// If generation is Some(n), returns those in generation n only.
410- pub fn get_objects ( & self , generation : Option < i32 > , owner : u32 ) -> Vec < PyObjectRef > {
410+ pub fn get_objects ( & self , generation : Option < i32 > , owner : GcOwner ) -> Vec < PyObjectRef > {
411411 fn collect_from_list (
412412 list : & LinkedList < GcLink , PyObject > ,
413- owner : u32 ,
413+ owner : GcOwner ,
414414 ) -> impl Iterator < Item = PyObjectRef > + ' _ {
415415 list. iter ( )
416416 . filter ( move |obj| is_owned_by ( obj, owner) )
@@ -1060,7 +1060,7 @@ impl GcState {
10601060 /// Freeze the objects `owner` could collect (move them to the permanent
10611061 /// generation).
10621062 /// Lock order: generation_lists[i] → permanent_list (consistent with unfreeze).
1063- fn freeze ( & self , owner : u32 ) {
1063+ fn freeze ( & self , owner : GcOwner ) {
10641064 let mut count = 0usize ;
10651065
10661066 for ( gen_idx, gen_list) in self . generation_lists . iter ( ) . enumerate ( ) {
@@ -1087,7 +1087,7 @@ impl GcState {
10871087
10881088 /// Unfreeze the objects `owner` froze (move them from permanent to gen2).
10891089 /// Lock order: generation_lists[2] → permanent_list (consistent with freeze).
1090- fn unfreeze ( & self , owner : u32 ) {
1090+ fn unfreeze ( & self , owner : GcOwner ) {
10911091 let mut count = 0usize ;
10921092
10931093 {
@@ -1148,7 +1148,7 @@ impl GcState {
11481148/// objects end up.
11491149pub struct GcInterpreterState {
11501150 /// Tag written into every object this interpreter tracks.
1151- owner : u32 ,
1151+ owner : GcOwner ,
11521152 /// Per-generation thresholds and statistics.
11531153 pub generations : [ GcGeneration ; 3 ] ,
11541154 /// GC enabled flag
@@ -1288,7 +1288,7 @@ impl Drop for GcInterpreterState {
12881288
12891289/// The tag `track_object` should write for the interpreter running now.
12901290#[ must_use]
1291- pub fn current_owner ( ) -> u32 {
1291+ pub fn current_owner ( ) -> GcOwner {
12921292 // SAFETY: the pointee is owned by the `PyGlobalState` of the VM on top of
12931293 // this thread's VM stack, which outlives the section this call runs in.
12941294 crate :: vm:: thread:: current_gc_state ( ) . map_or ( GC_NO_OWNER , |gc| unsafe { gc. as_ref ( ) } . owner )
0 commit comments