-
Notifications
You must be signed in to change notification settings - Fork 69
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Remove coordinator and support forking (#1067)
This PR removes the coordinator (a.k.a. controller) thread, and allows temporarily terminating and restarting all GC worker threads in order to support forking. Major changes include: - `GCController` is removed. All synchronization mechanisms involving the controller are removed, too. Important synchronization operations, such as opening buckets and declaring GC finished, are done by the last parked worker. The work packet `EndOfGC` is removed, and its job is now done by the last parked worker. - The `WorkerMonitor`, which previously synchronizes between GC workers, now also synchronizes between mutators and GC workers. This allows mutators to trigger GC by directly communicating with GC workers. - Introduced a new mechanism: "goals". Mutators can now request "goals", and GC workers will work on one goal at a time. Currently, a "goal" can be either GC or StopForFork. Triggering GC is now implemented as requesting the GC goal. - Added a pair of new APIs, namely `MMTK::prepare_to_fork()` and `MMTK::after_fork()`. VM bindings call them before and after forking to let the MMTK instance do proper preparation for forking. Fixes: #1053 Fixes: #1054
- Loading branch information
Showing
21 changed files
with
1,277 additions
and
579 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,42 @@ | ||
use crate::scheduler::GCWorkScheduler; | ||
use crate::vm::VMBinding; | ||
use std::marker::PhantomData; | ||
use std::sync::atomic::{AtomicBool, Ordering}; | ||
use std::sync::{Condvar, Mutex}; | ||
use std::sync::Arc; | ||
|
||
struct RequestSync { | ||
request_count: isize, | ||
last_request_count: isize, | ||
} | ||
|
||
/// GC requester. This object allows other threads to request (trigger) GC, | ||
/// and the GC coordinator thread waits for GC requests using this object. | ||
/// This data structure lets mutators trigger GC. | ||
pub struct GCRequester<VM: VMBinding> { | ||
request_sync: Mutex<RequestSync>, | ||
request_condvar: Condvar, | ||
/// Set by mutators to trigger GC. It is atomic so that mutators can check if GC has already | ||
/// been requested efficiently in `poll` without acquiring any mutex. | ||
request_flag: AtomicBool, | ||
phantom: PhantomData<VM>, | ||
} | ||
|
||
// Clippy says we need this... | ||
impl<VM: VMBinding> Default for GCRequester<VM> { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
scheduler: Arc<GCWorkScheduler<VM>>, | ||
} | ||
|
||
impl<VM: VMBinding> GCRequester<VM> { | ||
pub fn new() -> Self { | ||
pub fn new(scheduler: Arc<GCWorkScheduler<VM>>) -> Self { | ||
GCRequester { | ||
request_sync: Mutex::new(RequestSync { | ||
request_count: 0, | ||
last_request_count: -1, | ||
}), | ||
request_condvar: Condvar::new(), | ||
request_flag: AtomicBool::new(false), | ||
phantom: PhantomData, | ||
scheduler, | ||
} | ||
} | ||
|
||
/// Request a GC. Called by mutators when polling (during allocation) and when handling user | ||
/// GC requests (e.g. `System.gc();` in Java). | ||
pub fn request(&self) { | ||
if self.request_flag.load(Ordering::Relaxed) { | ||
return; | ||
} | ||
|
||
let mut guard = self.request_sync.lock().unwrap(); | ||
if !self.request_flag.load(Ordering::Relaxed) { | ||
self.request_flag.store(true, Ordering::Relaxed); | ||
guard.request_count += 1; | ||
self.request_condvar.notify_all(); | ||
if !self.request_flag.swap(true, Ordering::Relaxed) { | ||
// `GCWorkScheduler::request_schedule_collection` needs to hold a mutex to communicate | ||
// with GC workers, which is expensive for functions like `poll`. We use the atomic | ||
// flag `request_flag` to elide the need to acquire the mutex in subsequent calls. | ||
self.scheduler.request_schedule_collection(); | ||
} | ||
} | ||
|
||
/// Clear the "GC requested" flag so that mutators can trigger the next GC. | ||
/// Called by a GC worker when all mutators have come to a stop. | ||
pub fn clear_request(&self) { | ||
let guard = self.request_sync.lock().unwrap(); | ||
self.request_flag.store(false, Ordering::Relaxed); | ||
drop(guard); | ||
} | ||
|
||
pub fn wait_for_request(&self) { | ||
let mut guard = self.request_sync.lock().unwrap(); | ||
guard.last_request_count += 1; | ||
while guard.last_request_count == guard.request_count { | ||
guard = self.request_condvar.wait(guard).unwrap(); | ||
} | ||
} | ||
} |
Oops, something went wrong.