Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Replace GC tracking HashSet with intrusive linked list
Replace per-generation HashSet<GcObjectPtr> with intrusive doubly-linked
lists for GC object tracking. Each PyInner now carries gc_pointers
(prev/next) and gc_generation fields, enabling O(1) track/untrack
without hashing.

- Add gc_pointers (Pointers<PyObject>) and gc_generation (u8) to PyInner
- Implement GcLink trait for intrusive list integration
- Replace generation_objects/permanent_objects/tracked_objects/finalized_objects
  HashSets with generation_lists/permanent_list LinkedLists
- Use GcBits::FINALIZED flag instead of finalized_objects HashSet
- Change default_dealloc to untrack directly before memory free
- Hold both src/dst list locks in promote_survivors to prevent race
  conditions with concurrent untrack_object calls
- Add pop_front to LinkedList for freeze/unfreeze operations
  • Loading branch information
youknowone committed Mar 4, 2026
commit ff3b939186563d5dcd0a6a609e331468ec2d58eb
14 changes: 14 additions & 0 deletions crates/common/src/linked_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,20 @@ impl<L: Link> LinkedList<L, L::Target> {
// }
// }

/// Removes the first element from the list and returns it, or None if empty.
pub fn pop_front(&mut self) -> Option<L::Handle> {
let head = self.head?;
unsafe {
self.head = L::pointers(head).as_ref().get_next();
if let Some(new_head) = self.head {
L::pointers(new_head).as_mut().set_prev(None);
}
L::pointers(head).as_mut().set_next(None);
L::pointers(head).as_mut().set_prev(None);
Some(L::from_raw(head))
}
}

/// Returns whether the linked list does not contain any node
pub const fn is_empty(&self) -> bool {
self.head.is_none()
Expand Down
Loading