pub struct Thread { /* private fields */ }Expand description
GC Mutator.
By using this structure you can allocate, synchronize with GC and insert write barriers.
Implementations§
Source§impl Thread
impl Thread
pub fn safepoint_offset() -> usize
pub fn mark_queue_offset() -> usize
pub fn satb_buffer_offset() -> usize
pub fn satb_index_offset() -> usize
pub fn cm_in_progress_offset() -> usize
pub fn mark_ctx_offset() -> usize
pub fn mark_bitmap_offset() -> usize
pub fn tlab_start_offset() -> usize
pub fn tlab_top_offset() -> usize
pub fn tlab_end_offset() -> usize
pub fn tlab_bitmap_offset() -> usize
pub unsafe fn satb_mark_queue(&self) -> &LocalSSB
pub unsafe fn satb_mark_queue_mut(&mut self) -> &mut LocalSSB
Sourcepub fn allocate<T: 'static + Allocation>(&mut self, value: T) -> Handle<T>
pub fn allocate<T: 'static + Allocation>(&mut self, value: T) -> Handle<T>
Allocates fixed sized object on the heap.
Examples found in repository?
40fn create_tree(thread: &mut Thread, depth: i64) -> Handle<TreeNode> {
41 thread.safepoint();
42 let node = if 0 < depth {
43 let mut node = thread.allocate(TreeNode {
44 item: 0,
45 left: None,
46 right: None,
47 });
48
49 thread.write_barrier(node);
50 node.left = Some(create_tree(thread, depth - 1));
51 thread.write_barrier(node);
52 node.right = Some(create_tree(thread, depth - 1));
53
54 node
55 } else {
56 let node = TreeNode {
57 item: 0,
58 left: None,
59 right: None,
60 };
61
62 thread.allocate(node)
63 };
64
65 node
66}Sourcepub fn allocate_varsize<T: 'static + Allocation>(
&mut self,
length: usize,
) -> Handle<MaybeUninit<T>>
pub fn allocate_varsize<T: 'static + Allocation>( &mut self, length: usize, ) -> Handle<MaybeUninit<T>>
Allocates variably sized object on the heap.
Note that length field is automatically written at Allocation::VARSIZE_OFFSETOF_CAPACITY.
Sourcepub unsafe fn allocate_raw(&mut self, size: usize) -> *mut u8
pub unsafe fn allocate_raw(&mut self, size: usize) -> *mut u8
Allocates raw memory, unsafe to use outside of RSGC impl itself.
§TODO
I should really update it to include all code to properly tell GC that we allocated something, right now it is done in allocate and allocate_varsize but it should be done here.
Sourcepub fn write_barrier<T: Object + ?Sized>(&mut self, handle: Handle<T>)
pub fn write_barrier<T: Object + ?Sized>(&mut self, handle: Handle<T>)
SATB write barrier. Ensures that object processes all references correctly.
Must be inserted before write to handle.
Examples found in repository?
40fn create_tree(thread: &mut Thread, depth: i64) -> Handle<TreeNode> {
41 thread.safepoint();
42 let node = if 0 < depth {
43 let mut node = thread.allocate(TreeNode {
44 item: 0,
45 left: None,
46 right: None,
47 });
48
49 thread.write_barrier(node);
50 node.left = Some(create_tree(thread, depth - 1));
51 thread.write_barrier(node);
52 node.right = Some(create_tree(thread, depth - 1));
53
54 node
55 } else {
56 let node = TreeNode {
57 item: 0,
58 left: None,
59 right: None,
60 };
61
62 thread.allocate(node)
63 };
64
65 node
66}Sourcepub fn write_barrier_no_filter<T: Object + ?Sized>(&mut self, handle: Handle<T>)
pub fn write_barrier_no_filter<T: Object + ?Sized>(&mut self, handle: Handle<T>)
Same as write_barrier but does not filter marked objects, instead they are filtered
when flushing SATB buffer to collector.
Sourcepub unsafe fn raw_write_barrier<const FILTER_SATB: bool>(
&mut self,
obj: *mut HeapObjectHeader,
)
pub unsafe fn raw_write_barrier<const FILTER_SATB: bool>( &mut self, obj: *mut HeapObjectHeader, )
Raw implementation of write-barrier.
If SATB mode is used this code will do Yuasa deletion write barrier that captures writes to white objects. Note that this barrier is very conservative: it does not check colors of new values that are being written.
In Incremental Update mode uses Steele’s write barrier that captures black<-white writes. This barrier is very conservative as well. Note that with IU mode concurrent mark termination might take longer.
In passive mode does nothing.
Sourcepub fn flush_ssb(&mut self)
pub fn flush_ssb(&mut self)
Flush SSB queue. This function is called when SSB queue is full.
Writes are pushed to global SATB queue. If object is already marked it is not pushed to SATB queue.
pub fn atomic_gc_state(&self) -> &AtomicI8
pub unsafe fn gc_state_set(&mut self, state: i8, old_state: i8) -> i8
pub unsafe fn set_last_sp(&mut self, sp: *mut u8)
pub unsafe fn state_save_and_set(&mut self, state: i8) -> i8
pub fn stack_start(&self) -> *mut u8
pub fn last_sp(&self) -> *mut u8
Sourcepub unsafe fn safepoint_page(&self) -> *mut u8
pub unsafe fn safepoint_page(&self) -> *mut u8
Returns pointer to safepoint page. When JITing your code you can directly inline safepoint poll into your code.
Sourcepub const fn is_conditional_safepoint() -> bool
pub const fn is_conditional_safepoint() -> bool
Returns true if safepoints are conditional in this build of RSGC.
Sourcepub fn safepoint(&mut self)
pub fn safepoint(&mut self)
Reads from polling page. If safepoint is disabled nothing happens but when safepoint is enabled this triggers page fault (SIGSEGV/SIGBUS on Linux/macOS/BSD) and goes into signal to suspend thread.
§Note
Enable conditional-safepoint feature when running in LLDB/GDB, otherwise safepoint events
will be treatened as segfault by debuggers.
Examples found in repository?
40fn create_tree(thread: &mut Thread, depth: i64) -> Handle<TreeNode> {
41 thread.safepoint();
42 let node = if 0 < depth {
43 let mut node = thread.allocate(TreeNode {
44 item: 0,
45 left: None,
46 right: None,
47 });
48
49 thread.write_barrier(node);
50 node.left = Some(create_tree(thread, depth - 1));
51 thread.write_barrier(node);
52 node.right = Some(create_tree(thread, depth - 1));
53
54 node
55 } else {
56 let node = TreeNode {
57 item: 0,
58 left: None,
59 right: None,
60 };
61
62 thread.allocate(node)
63 };
64
65 node
66}Sourcepub fn is_registered(&self) -> bool
pub fn is_registered(&self) -> bool
Returns true if thread is registered in a GC.
Sourcepub fn current() -> &'static mut Thread
pub fn current() -> &'static mut Thread
Returns current thread.
Examples found in repository?
68fn bench_parallel() {
69
70 let mut n = 0;
71 if let Some(arg) = std::env::args().skip(1).next() {
72 if let Ok(x) = arg.parse::<usize>() {
73 n = x;
74 }
75 }
76
77 let min_depth = 4;
78 let max_depth = if n < (min_depth + 2) {
79 min_depth + 2
80 } else {
81 n
82 };
83
84 let start = std::time::Instant::now();
85 let stretch_depth = max_depth + 1;
86
87 {
88 println!(
89 "stretch tree of depth {}\t check: {}",
90 stretch_depth,
91 create_tree(Thread::current(), stretch_depth as _)
92 .as_ref()
93 .check_tree()
94 );
95 }
96
97 let long_lasting_tree = create_tree(Thread::current(), max_depth as _);
98 use parking_lot::Mutex;
99 let results = Arc::new(
100 (0..(max_depth - min_depth) / 2 + 1)
101 .map(|_| Mutex::new(String::new()))
102 .collect::<Vec<_>>(),
103 );
104 rsgc::thread::scoped::scoped(|scope| {
105 let mut d = min_depth;
106
107 while d <= max_depth {
108 let depth = d;
109 let cloned = results.clone();
110 scope.spawn(move || {
111 let thread = Thread::current();
112 let iterations = 1 << (max_depth - depth + min_depth);
113 let mut check = 0;
114 for _ in 1..=iterations {
115 let tree_node = create_tree(thread, depth as _);
116 check += tree_node.as_ref().check_tree();
117 }
118
119 *cloned[(depth - min_depth) / 2].lock() = format!(
120 "{}\t trees of depth {}\t check: {}",
121 iterations, depth, check
122 );
123 });
124
125 d += 2;
126 }
127 });
128 for result in results.iter() {
129 println!("{}", *result.lock());
130 }
131 println!(
132 "long lived tree of depth {}\t check: {}",
133 max_depth,
134 long_lasting_tree.as_ref().check_tree()
135 );
136
137 println!(
138 "time: {}ms",
139 start.elapsed().as_millis()
140 );
141}