Retiring Objects¶
Understanding how to retire objects for safe reclamation.
State Machine¶
Overview¶
When you remove an object from a lock-free data structure, you cannot immediately free it - other threads might still be accessing it. Instead, you retire the object, marking it for later reclamation when safe.
The Managed Type¶
DEBRA uses the Managed[T] wrapper type to track objects that need epoch-based reclamation:
type
NodeObj = object
value: int
next: Atomic[Managed[ref NodeObj]]
Node = ref NodeObj
# Create a managed node - GC won't collect until retired
let node = managed Node(value: 42)
The managed() proc calls GC_ref internally, preventing Nim's garbage collector from freeing the object. Only DEBRA's reclamation process (via GC_unref) can free it.
Self-Referential Types¶
When a type references itself (like linked list nodes), use the ref Obj pattern:
# CORRECT - use ref Obj pattern for self-reference
type
NodeObj = object
value: int
next: Atomic[Managed[ref NodeObj]] # Self-reference works
Node = ref NodeObj
# INCORRECT - ref object inline won't work
type
Node = ref object
value: int
next: Atomic[Managed[Node]] # Won't compile
This is a Nim limitation with generic distinct types and forward references.
Basic Retirement¶
You must be pinned to retire objects:
# examples/retire_single.nim
## Single object retirement example.
import debra
import std/atomics
type
NodeObj = object
value: int
next: Atomic[Managed[ref NodeObj]]
Node = ref NodeObj
proc main() =
var manager = initDebraManager[4](../../examples)
setGlobalManager(addr manager)
let handle = registerThread(manager)
# Enter critical section
let pinned = unpinned(handle).pin()
# Create a managed node
let node = managed Node(value: 42)
echo "Created node with value: ", node.value
# Retire the node
let ready = retireReady(pinned)
discard ready.retire(node)
echo "Node retired for later reclamation"
# Exit critical section
discard pinned.unpin()
echo "Single retirement example completed"
when isMainModule:
main()
Multiple Object Retirement¶
When retiring multiple objects in a single critical section, use retireReadyFromRetired() to chain retirements:
# examples/retire_multiple.nim
## Multiple object retirement example.
import debra
import std/atomics
type
NodeObj = object
value: int
next: Atomic[Managed[ref NodeObj]]
Node = ref NodeObj
proc main() =
var manager = initDebraManager[4](../../examples)
setGlobalManager(addr manager)
let handle = registerThread(manager)
# Enter critical section
let pinned = unpinned(handle).pin()
# Retire multiple nodes in a single critical section
var ready = retireReady(pinned)
for i in 1..5:
let node = managed Node(value: i * 10)
echo "Retiring node with value: ", node.value
let retired = ready.retire(node)
ready = retireReadyFromRetired(retired)
echo "Retired 5 nodes"
# Exit critical section
discard pinned.unpin()
echo "Multiple retirement example completed"
when isMainModule:
main()
Accessing Managed Fields¶
The Managed[T] type provides transparent field access:
let node = managed Node(value: 42, name: "test")
# Direct field access via dot template
echo node.value # 42
echo node.name # "test"
# When you need the actual ref
doSomething(node.inner)
Limbo Bags¶
Retired objects are stored in thread-local limbo bags:
- Each bag holds up to 64 objects
- Bags are chained together by epoch
- Reclamation walks bags from oldest to newest
Retirement Timing¶
Always unlink first, then retire:
# RIGHT - retire after unlinking
if head.compareExchange(oldHead, next, moRelease, moRelaxed):
let ready = retireReady(pinned)
discard ready.retire(oldHead)
# WRONG - retire before unlinking (unsafe!)
let ready = retireReady(pinned)
discard ready.retire(oldHead)
head.store(next, moRelease)
Best Practices¶
Do Retire Objects That:¶
- Were removed from shared data structures
- Are no longer reachable via shared pointers
- Might still be accessed by concurrent threads
Don't Retire Objects That:¶
- Are still reachable in the data structure
- Are local to the current thread (just let them go out of scope)
- Are static/global (they're never freed)
Next Steps¶
- Learn about reclamation
- Understand neutralization
- See integration examples