-
Notifications
You must be signed in to change notification settings - Fork 69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inconsistent mutability of GCWorker
across VM interface
#522
Comments
I think the problem is that the scheduler does not really own the worker. If the scheduler owned the worker, it would have unrestricted access to its fields. For example, the scheduler should be able to read and modify its I think:
I suggest letting the worker thread own the GCWorker. This implies change the To communicate with the scheduler, isolate the struct GcWorkerCommunicator {
pub parked: AtomicBool, // Atomic.
pub local_work_bucket: WorkBucket<VM>, // Already well-synchronized
pub stat_enabled: AtomicBool, // Atomic,
}
struct Scheduler {
worker_communicators: Vec<Arc<GcWorkerCommunicator<VM>>>,
}
struct Worker {
// ...
communicator: Arc<GcWorkerCommunicator<VM>>,
stat: WorkerLocalStat, // Needs to be synchornised
// ...
} And I am afraid the implementation of pub fn merge<C>(&mut self, stat: &WorkerLocalStat<C>) { // NOTE: stat is a &
// Merge work packet type ID to work packet name mapping
for (id, name) in &stat.work_id_name_map { // ERROR: We assume stat cannot be changed, but not really.
self.work_id_name_map.insert(*id, *name);
} The |
I totally agree with what you said about GC worker. The GC thread should own its GC worker, and separating the global part and the local part is a favorable pattern that we are using. As for the |
The The following example shows how one thread can notify another thread to temporarily surrender its borrow so it can access the shared data mutably. If you set the use std::env::args;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::sync::Arc;
use atomic_refcell::AtomicRefCell;
use std::thread;
struct Wallet {
money: AtomicRefCell<i32>,
}
struct Pedestrian {
wallet: Arc<Wallet>,
sender: Sender<Message>,
receiver: Receiver<Message>,
}
struct Robber {
wallet: Arc<Wallet>,
sender: Sender<Message>,
receiver: Receiver<Message>,
}
#[derive(PartialEq)]
enum Message {
SurrenderYourMoney,
DontHurtMe,
Leave,
}
fn main() {
let nice = true;
let wallet = Arc::new(Wallet {
money: AtomicRefCell::new(0),
});
let (rtp_sender, rtp_receiver) = channel();
let (ptr_sender, ptr_receiver) = channel();
let pedestrian = Pedestrian {
wallet: wallet.clone(),
sender: ptr_sender,
receiver: rtp_receiver,
};
let robber = Robber {
wallet: wallet.clone(),
sender: rtp_sender,
receiver: ptr_receiver,
};
let pedestrian_thread = thread::spawn(move || {
let mut handle = pedestrian.wallet.money.borrow_mut();
*handle = 100;
let msg = pedestrian.receiver.recv().unwrap();
assert!(msg == Message::SurrenderYourMoney);
if nice {
println!("Okay I'll give you!");
drop(handle);
} else {
println!("No!");
}
pedestrian.sender.send(Message::DontHurtMe).unwrap();
let msg = pedestrian.receiver.recv().unwrap();
assert!(msg == Message::Leave);
});
let robber_thread = thread::spawn(move || {
robber.sender.send(Message::SurrenderYourMoney).unwrap();
let msg = robber.receiver.recv().unwrap();
assert!(msg == Message::DontHurtMe);
let mut handle = robber.wallet.money.borrow_mut();
let my_money = *handle;
*handle = 0;
println!("I got ${}", my_money);
robber.sender.send(Message::Leave).unwrap();
});
pedestrian_thread.join().unwrap();
robber_thread.join().unwrap();
} |
spawn_worker_thread
should pass &mut GCWorker
GCWorker
across VM interface
This commit fixes an inconsistency in the VMCollection interface where a GCWorker is exposed to the binding via `Collection::spawn_worker_thread` as a `&GCWorker`, but later received from the binding via `memory_manager::start_worker` as a `&mut GCWorker`. The root cause is because GCWorker is wrongly owned by the scheduler. We make each GC worker thread the owner of its `GCWorker` struct, and we pass the `GCWorker` struct across API boundary as owning `Box`, fixing the interface. We isolate the part of `GCWorker` shared with the GC scheduler into a `GCWorkerShared` struct, and ensure the fields are properly synchronized. Particularly, we now use `AtomicRefCell` for `WorkerLocalStat`. `AtomicRefCell` allows it to be borrowed mutably by the GC worker and the mutator (via `harness_begin/end` methods) at different time. However, it is a known issue that in concurrent GC, it is possible for GC to happen when `harness_begin/end` is called. In that case, it will panic. Fixes: mmtk#522
This commit fixes an inconsistency in the VMCollection interface where a GCWorker is exposed to the binding via `Collection::spawn_worker_thread` as a `&GCWorker`, but later received from the binding via `memory_manager::start_worker` as a `&mut GCWorker`. The root cause is because GCWorker is wrongly owned by the scheduler. We make each GC worker thread the owner of its `GCWorker` struct, and we pass the `GCWorker` struct across API boundary as owning `Box`, fixing the interface. We isolate the part of `GCWorker` shared with the GC scheduler into a `GCWorkerShared` struct, and ensure the fields are properly synchronized. Particularly, we now use `AtomicRefCell` for `WorkerLocalStat`. `AtomicRefCell` allows it to be borrowed mutably by the GC worker and the mutator (via `harness_begin/end` methods) at different time. However, it is a known issue that in concurrent GC, it is possible for GC to happen when `harness_begin/end` is called. In that case, it will panic. Fixes: mmtk#522
This commit fixes an inconsistency in the VMCollection interface where a GCWorker is exposed to the binding via `Collection::spawn_worker_thread` as a `&GCWorker`, but later received from the binding via `memory_manager::start_worker` as a `&mut GCWorker`. The root cause is because GCWorker is wrongly owned by the scheduler. We make each GC worker thread the owner of its `GCWorker` struct, and we pass the `GCWorker` struct across API boundary as owning `Box`, fixing the interface. We isolate the part of `GCWorker` shared with the GC scheduler into a `GCWorkerShared` struct, and ensure the fields are properly synchronized. Particularly, we now use `AtomicRefCell` for `WorkerLocalStat`. `AtomicRefCell` allows it to be borrowed mutably by the GC worker and the mutator (via `harness_begin/end` methods) at different time. However, it is a known issue that in concurrent GC, it is possible for GC to happen when `harness_begin/end` is called. In that case, it will panic. Fixes: mmtk#522
This commit fixes an inconsistency in the VMCollection interface where a GCWorker is exposed to the binding via `Collection::spawn_worker_thread` as a `&GCWorker`, but later received from the binding via `memory_manager::start_worker` as a `&mut GCWorker`. The root cause is because GCWorker is wrongly owned by the scheduler. We make each GC worker thread the owner of its `GCWorker` struct, and we pass the `GCWorker` struct across API boundary as owning `Box`, fixing the interface. We isolate the part of `GCWorker` shared with the GC scheduler into a `GCWorkerShared` struct, and ensure the fields are properly synchronized. Particularly, we now use `AtomicRefCell` for `WorkerLocalStat`. `AtomicRefCell` allows it to be borrowed mutably by the GC worker and the mutator (via `harness_begin/end` methods) at different time. However, it is a known issue that in concurrent GC, it is possible for GC to happen when `harness_begin/end` is called. In that case, it will panic. Fixes: mmtk#522
This commit fixes an inconsistency in the VMCollection interface where a GCWorker is exposed to the binding via `Collection::spawn_worker_thread` as a `&GCWorker`, but later received from the binding via `memory_manager::start_worker` as a `&mut GCWorker`. The root cause is because GCWorker is wrongly owned by the scheduler. We make each GC worker thread the owner of its `GCWorker` struct, and we pass the `GCWorker` struct across API boundary as owning `Box`, fixing the interface. We isolate the part of `GCWorker` shared with the GC scheduler into a `GCWorkerShared` struct, and ensure the fields are properly synchronized. Particularly, we now use `AtomicRefCell` for `WorkerLocalStat`. `AtomicRefCell` allows it to be borrowed mutably by the GC worker and the mutator (via `harness_begin/end` methods) at different time. However, it is a known issue that in concurrent GC, it is possible for GC to happen when `harness_begin/end` is called. In that case, it will panic. Fixes: mmtk#522
This commit fixes an inconsistency in the VMCollection interface where a GCWorker is exposed to the binding via `Collection::spawn_worker_thread` as a `&GCWorker`, but later received from the binding via `memory_manager::start_worker` as a `&mut GCWorker`. The root cause is because GCWorker is wrongly owned by the scheduler. We make each GC worker thread the owner of its `GCWorker` struct, and we pass the `GCWorker` struct across API boundary as owning `Box`, fixing the interface. We isolate the part of `GCWorker` shared with the GC scheduler into a `GCWorkerShared` struct, and ensure the fields are properly synchronized. Particularly, we now use `AtomicRefCell` for `WorkerLocalStat`. `AtomicRefCell` allows it to be borrowed mutably by the GC worker and the mutator (via `harness_begin/end` methods) at different time. However, it is a known issue that in concurrent GC, it is possible for GC to happen when `harness_begin/end` is called. In that case, it will panic. Fixes: mmtk#522
This commit fixes an inconsistency in the VMCollection interface where a GCWorker is exposed to the binding via `Collection::spawn_worker_thread` as a `&GCWorker`, but later received from the binding via `memory_manager::start_worker` as a `&mut GCWorker`. The root cause is because GCWorker is wrongly owned by the scheduler. We make each GC worker thread the owner of its `GCWorker` struct, and we pass the `GCWorker` struct across API boundary as owning `Box`, fixing the interface. We isolate the part of `GCWorker` shared with the GC scheduler into a `GCWorkerShared` struct, and ensure the fields are properly synchronized. Particularly, we now use `AtomicRefCell` for `WorkerLocalStat`. `AtomicRefCell` allows it to be borrowed mutably by the GC worker and the mutator (via `harness_begin/end` methods) at different time. However, it is a known issue that in concurrent GC, it is possible for GC to happen when `harness_begin/end` is called. In that case, it will panic. Fixes: mmtk#522
This commit fixes an inconsistency in the VMCollection interface where a GCWorker is exposed to the binding via `Collection::spawn_worker_thread` as a `&GCWorker`, but later received from the binding via `memory_manager::start_worker` as a `&mut GCWorker`. The root cause is because GCWorker is wrongly owned by the scheduler. We make each GC worker thread the owner of its `GCWorker` struct, and we pass the `GCWorker` struct across API boundary as owning `Box`, fixing the interface. We isolate the part of `GCWorker` shared with the GC scheduler into a `GCWorkerShared` struct, and ensure the fields are properly synchronized. Particularly, we now use `AtomicRefCell` for `WorkerLocalStat`. `AtomicRefCell` allows it to be borrowed mutably by the GC worker and the mutator (via `harness_begin/end` methods) at different time. However, it is a known issue that in concurrent GC, it is possible for GC to happen when `harness_begin/end` is called. In that case, it will panic. Fixes: mmtk#522
This commit fixes an inconsistency in the VMCollection interface where a GCWorker is exposed to the binding via `Collection::spawn_worker_thread` as a `&GCWorker`, but later received from the binding via `memory_manager::start_worker` as a `&mut GCWorker`. The root cause is because GCWorker is wrongly owned by the scheduler. We make each GC worker thread the owner of its `GCWorker` struct, and we pass the `GCWorker` struct across API boundary as owning `Box`, fixing the interface. We isolate the part of `GCWorker` shared with the GC scheduler into a `GCWorkerShared` struct, and ensure the fields are properly synchronized. Particularly, we now use `AtomicRefCell` for `WorkerLocalStat`. `AtomicRefCell` allows it to be borrowed mutably by the GC worker and the mutator (via `harness_begin/end` methods) at different time. However, it is a known issue that in concurrent GC, it is possible for GC to happen when `harness_begin/end` is called. In that case, it will panic. Fixes: #522
Currently,
Collection<VM>::spawn_worker_thread
provides actx: Option<&GCWorker<VM>>
parameter, butmemory_manager::start_worker<VM>
requires aworker: &mut GCWorker<VM>
parameter.The provided parameter is immutable, but the required parameter is mutable. Since
spawn_worker_thread
is supposed to create a thread that eventually callsstart_worker
, thectx
argument, ifSome(worker)
should be passed tostart_worker
. Now it is a compilation error.In the following example, I am creating the GC threads directly in Rust, without involving VM-specific C functions.
Currently, in
mmtk-openjdk
, the&GCWorker
is force-cast to*mut GCWorker
before passing to C++:Update
After discussion, we agree that the GC worker thread should own the
GCWorker
data structure.The scheduler needs to communicate with GC workers, so shared data structures should be isolated, and should be accessed with proper synchornisation.
The
stat
field is written into by the GC worker during GC, but read from by the scheduler duringharness_end
(in mutator).harness_end
never happens when GC is running, so there should be no data race. The atomic_refcell crate provides a safe and cheap way to handle such case.The text was updated successfully, but these errors were encountered: