- 
                Notifications
    
You must be signed in to change notification settings  - Fork 13.9k
 
Description
These will serve as enhanced versions of arc::exclusive. The plan is for mutex_arc to be the same as exclusive, but scheduler enabled, and come equipped with a working condition variable. It is marked unsafe because you can still create cycles with it (benefit: you can nest them).
rw_arc is somewhat more advanced, and notably more safe. The const serves two purposes - it allows handing out immutable references while in read mode (just like arc::arc does today), and it also prevents nesting them inside each other, since they won't be const themselves.
I am also thinking of exposing semaphores, with acquire and release and potentially also cond_wait and cond_signal. These wouldn't protect anything themselves, but could perhaps be used to synchronise beyond-rust shared resources, such as the filesystem.
Proposed interface:
trait condvar {
    fn signal();
    fn wait();
}
impl <T: send> for &mutex_arc<T> {
    unsafe fn access<U>(blk: fn(&mut T) -> U) -> U;
    unsafe fn access_cond<U>(blk: fn(&mut T, condvar) -> U) -> U;
}
impl <T: const send> for &rw_arc<T> {
    // Read mode
    fn access_read<U>(blk: fn(&T) -> U) -> U;
    // Write mode
    fn access<U>(blk: fn(&mut T) -> U) -> U;
    fn access_cond<U>(blk: fn(&mut T, &condvar) -> U) -> U;
    fn access_downgrade<U>(blk: fn(+write_mode<T>) -> U) -> U;
}
fn downgrade<T: const send>(+write_mode<T>) -> read_mode<T>;
impl <T: const send> for &write_mode<T> {
    fn access<U>(blk: fn(&mut T) -> U) -> U;
    fn access_cond<U>(blk: fn(&mut T, &condvar) -> U) -> U;
}
impl <T: const send> for &read_mode<T> {
    fn access<U>(blk: fn(&T) -> U) -> U;
}
A couple points:
- The condvar is just like 
rust_cond_lockvery-unsafely provided in the past. 
cvar example:
do mutex_arc.access_cond |state, cond| {
    ...
    while not_satisfied(state) {
        cond.wait();
    }
    ...
}
- I don't think it's meaningful to hand out a condition variable for rws in read-mode. And it'd be a bunch nastier to implement. Feel free to argue, but I think that (a) signalling on one is meaningless, since you can't have changed anything inside, and (b) waiting on one is meaningless, because either you forbid writers from going before you wake (in which case what are you waiting for?) or writers can go (in which case you might as well have dropped the lock wholesale).
 - Downgrade is really neat (hopefully). The 
read_modeandwrite_modeare linear tokens that allow you to access the state, and downgrade consumes the write mode. This allows you atomically downgrade without releasing the lock, while statically enforcing no mutation after the downgrade. 
Downgrade example:
do rw_arc.access_downgrade |write_mode| {
    do write_mode.access |state| {
        ... mutate state ...
    }
    let read_mode = downgrade(write_mode);
    do read_mode.access |state| {
        ... state is immutable ...
    }
}
In particular, I would like confirmation that my understanding of region pointers will enforce the im/mutability properties.