Skip to content

Commit 29afb0c

Browse files
authored
Introduce a context object for GC controller thread (#533)
* Introduce context for the GC controller thread This commit introduces the `GCController` struct. It is owned by the GC controller thread. It owns the `GCWorker` for the controller, and has references to objects that it needs to communicate with other threads. Previously, those dependencies were scattered in `ControllerCollectorContext` and `GCWorkScheduler`, which complicated the initialization of the MMTk instance and the GC controller thread. * Move controller functions to GCController Move the GCWorkScheduler::wait_for_completion method to the GCController type. This allows us to move controller-specific fields away from GCWorkScheduler, too. * Miscellaneous fixes. - Renamed ControllerCollectorContext to GCRequester - Removed initializer and finalizer functions from GCWorkScheduler - The embedded GCController is no longer boxed. - Added comments - Minor adjustment to API functions. - Other minor fixes.
1 parent 4ebb6b6 commit 29afb0c

File tree

25 files changed

+336
-342
lines changed

25 files changed

+336
-342
lines changed

docs/tutorial/code/mygc_semispace/global.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,8 @@ impl<VM: VMBinding> Plan for MyGC<VM> {
7979
&mut self,
8080
heap_size: usize,
8181
vm_map: &'static VMMap,
82-
scheduler: &Arc<GCWorkScheduler<VM>>,
8382
) {
84-
self.common.gc_init(heap_size, vm_map, scheduler);
83+
self.common.gc_init(heap_size, vm_map);
8584
self.copyspace0.init(&vm_map);
8685
self.copyspace1.init(&vm_map);
8786
}

examples/mmtk.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ extern void mmtk_scan_region();
8686
extern void mmtk_handle_user_collection_request(void* tls);
8787

8888
// Run the main loop for the GC controller thread. Does not return
89-
extern void mmtk_start_control_collector(void* tls);
89+
extern void mmtk_start_control_collector(void* tls, void* worker);
9090

9191
// Run the main loop for a GC worker. Does not return
9292
extern void mmtk_start_worker(void* tls, void* worker);

src/memory_manager.rs

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,16 @@ use crate::mmtk::MMTK;
1515
use crate::plan::AllocationSemantics;
1616
use crate::plan::{Mutator, MutatorContext};
1717
use crate::scheduler::WorkBucketStage;
18-
use crate::scheduler::{GCWork, GCWorker};
18+
use crate::scheduler::{GCController, GCWork, GCWorker};
1919
use crate::util::alloc::allocators::AllocatorSelector;
2020
use crate::util::constants::{LOG_BYTES_IN_PAGE, MIN_OBJECT_SIZE};
2121
use crate::util::heap::layout::vm_layout_constants::HEAP_END;
2222
use crate::util::heap::layout::vm_layout_constants::HEAP_START;
2323
use crate::util::opaque_pointer::*;
2424
use crate::util::{Address, ObjectReference};
25-
use crate::vm::Collection;
2625
use crate::vm::VMBinding;
2726
use std::sync::atomic::Ordering;
2827

29-
/// Run the main loop for the GC controller thread. This method does not return.
30-
///
31-
/// Arguments:
32-
/// * `mmtk`: A reference to an MMTk instance.
33-
/// * `tls`: The thread that will be used as the GC controller.
34-
pub fn start_control_collector<VM: VMBinding>(mmtk: &MMTK<VM>, tls: VMWorkerThread) {
35-
mmtk.plan.base().control_collector_context.run(tls);
36-
}
37-
3828
/// Initialize an MMTk instance. A VM should call this method after creating an [MMTK](../mmtk/struct.MMTK.html)
3929
/// instance but before using any of the methods provided in MMTk. This method will attempt to initialize a
4030
/// logger. If the VM would like to use its own logger, it should initialize the logger before calling this method.
@@ -69,8 +59,7 @@ pub fn gc_init<VM: VMBinding>(mmtk: &'static mut MMTK<VM>, heap_size: usize) {
6959
}
7060
}
7161
assert!(heap_size > 0, "Invalid heap size");
72-
mmtk.plan
73-
.gc_init(heap_size, &crate::VM_MAP, &mmtk.scheduler);
62+
mmtk.plan.gc_init(heap_size, &crate::VM_MAP);
7463
info!("Initialized MMTk with {:?}", *mmtk.options.plan);
7564
#[cfg(feature = "extreme_assertions")]
7665
warn!("The feature 'extreme_assertions' is enabled. MMTk will run expensive run-time checks. Slow performance should be expected.");
@@ -163,36 +152,51 @@ pub fn get_allocator_mapping<VM: VMBinding>(
163152
mmtk.plan.get_allocator_mapping()[semantics]
164153
}
165154

155+
/// Run the main loop for the GC controller thread. This method does not return.
156+
///
157+
/// Arguments:
158+
/// * `tls`: The thread that will be used as the GC controller.
159+
/// * `gc_controller`: The execution context of the GC controller threa.
160+
/// It is the `GCController` passed to `Collection::spawn_gc_thread`.
161+
/// * `mmtk`: A reference to an MMTk instance.
162+
pub fn start_control_collector<VM: VMBinding>(
163+
_mmtk: &'static MMTK<VM>,
164+
tls: VMWorkerThread,
165+
gc_controller: &mut GCController<VM>,
166+
) {
167+
gc_controller.run(tls);
168+
}
169+
166170
/// Run the main loop of a GC worker. This method does not return.
167171
///
168172
/// Arguments:
169173
/// * `tls`: The thread that will be used as the GC worker.
170-
/// * `worker`: A reference to the GC worker.
174+
/// * `worker`: The execution context of the GC worker thread.
175+
/// It is the `GCWorker` passed to `Collection::spawn_gc_thread`.
171176
/// * `mmtk`: A reference to an MMTk instance.
172177
pub fn start_worker<VM: VMBinding>(
178+
mmtk: &'static MMTK<VM>,
173179
tls: VMWorkerThread,
174180
worker: &mut GCWorker<VM>,
175-
mmtk: &'static MMTK<VM>,
176181
) {
177182
worker.run(tls, mmtk);
178183
}
179184

180185
/// Initialize the scheduler and GC workers that are required for doing garbage collections.
181186
/// This is a mandatory call for a VM during its boot process once its thread system
182-
/// is ready. This should only be called once. This call will invoke Collection::spawn_worker_thread()
187+
/// is ready. This should only be called once. This call will invoke Collection::spawn_gc_thread()
183188
/// to create GC threads.
184189
///
185190
/// Arguments:
186191
/// * `mmtk`: A reference to an MMTk instance.
187192
/// * `tls`: The thread that wants to enable the collection. This value will be passed back to the VM in
188-
/// Collection::spawn_worker_thread() so that the VM knows the context.
193+
/// Collection::spawn_gc_thread() so that the VM knows the context.
189194
pub fn initialize_collection<VM: VMBinding>(mmtk: &'static MMTK<VM>, tls: VMThread) {
190195
assert!(
191196
!mmtk.plan.is_initialized(),
192197
"MMTk collection has been initialized (was initialize_collection() already called before?)"
193198
);
194199
mmtk.scheduler.initialize(*mmtk.options.threads, mmtk, tls);
195-
VM::VMCollection::spawn_worker_thread(tls, None); // spawn controller thread
196200
mmtk.plan.base().initialized.store(true, Ordering::SeqCst);
197201
}
198202

src/plan/controller_collector_context.rs

Lines changed: 0 additions & 106 deletions
This file was deleted.

src/plan/gc_requester.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use crate::vm::VMBinding;
2+
use std::marker::PhantomData;
3+
use std::sync::atomic::{AtomicBool, Ordering};
4+
use std::sync::{Condvar, Mutex};
5+
6+
struct RequestSync {
7+
request_count: isize,
8+
last_request_count: isize,
9+
}
10+
11+
/// GC requester. This object allows other threads to request (trigger) GC,
12+
/// and the GC coordinator thread waits for GC requests using this object.
13+
pub struct GCRequester<VM: VMBinding> {
14+
request_sync: Mutex<RequestSync>,
15+
request_condvar: Condvar,
16+
request_flag: AtomicBool,
17+
phantom: PhantomData<VM>,
18+
}
19+
20+
// Clippy says we need this...
21+
impl<VM: VMBinding> Default for GCRequester<VM> {
22+
fn default() -> Self {
23+
Self::new()
24+
}
25+
}
26+
27+
impl<VM: VMBinding> GCRequester<VM> {
28+
pub fn new() -> Self {
29+
GCRequester {
30+
request_sync: Mutex::new(RequestSync {
31+
request_count: 0,
32+
last_request_count: -1,
33+
}),
34+
request_condvar: Condvar::new(),
35+
request_flag: AtomicBool::new(false),
36+
phantom: PhantomData,
37+
}
38+
}
39+
40+
pub fn request(&self) {
41+
if self.request_flag.load(Ordering::Relaxed) {
42+
return;
43+
}
44+
45+
let mut guard = self.request_sync.lock().unwrap();
46+
if !self.request_flag.load(Ordering::Relaxed) {
47+
self.request_flag.store(true, Ordering::Relaxed);
48+
guard.request_count += 1;
49+
self.request_condvar.notify_all();
50+
}
51+
}
52+
53+
pub fn clear_request(&self) {
54+
let guard = self.request_sync.lock().unwrap();
55+
self.request_flag.store(false, Ordering::Relaxed);
56+
drop(guard);
57+
}
58+
59+
pub fn wait_for_request(&self) {
60+
let mut guard = self.request_sync.lock().unwrap();
61+
guard.last_request_count += 1;
62+
while guard.last_request_count == guard.request_count {
63+
guard = self.request_condvar.wait(guard).unwrap();
64+
}
65+
}
66+
}

src/plan/generational/copying/global.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,8 @@ impl<VM: VMBinding> Plan for GenCopy<VM> {
7272
self.gen.last_collection_full_heap()
7373
}
7474

75-
fn gc_init(
76-
&mut self,
77-
heap_size: usize,
78-
vm_map: &'static VMMap,
79-
scheduler: &Arc<GCWorkScheduler<VM>>,
80-
) {
81-
self.gen.gc_init(heap_size, vm_map, scheduler);
75+
fn gc_init(&mut self, heap_size: usize, vm_map: &'static VMMap) {
76+
self.gen.gc_init(heap_size, vm_map);
8277
self.copyspace0.init(vm_map);
8378
self.copyspace1.init(vm_map);
8479
}

src/plan/generational/global.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,8 @@ impl<VM: VMBinding> Gen<VM> {
7474
}
7575

7676
/// Initialize Gen. This should be called by the gc_init() API call.
77-
pub fn gc_init(
78-
&mut self,
79-
heap_size: usize,
80-
vm_map: &'static VMMap,
81-
scheduler: &Arc<GCWorkScheduler<VM>>,
82-
) {
83-
self.common.gc_init(heap_size, vm_map, scheduler);
77+
pub fn gc_init(&mut self, heap_size: usize, vm_map: &'static VMMap) {
78+
self.common.gc_init(heap_size, vm_map);
8479
self.nursery.init(vm_map);
8580
}
8681

src/plan/generational/immix/global.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,8 @@ impl<VM: VMBinding> Plan for GenImmix<VM> {
9797
self.gen.collection_required(self, space_full, space)
9898
}
9999

100-
fn gc_init(
101-
&mut self,
102-
heap_size: usize,
103-
vm_map: &'static VMMap,
104-
scheduler: &Arc<GCWorkScheduler<VM>>,
105-
) {
106-
self.gen.gc_init(heap_size, vm_map, scheduler);
100+
fn gc_init(&mut self, heap_size: usize, vm_map: &'static VMMap) {
101+
self.gen.gc_init(heap_size, vm_map);
107102
self.immix.init(vm_map);
108103
}
109104

0 commit comments

Comments
 (0)