Skip to content
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

Add the generalized-scope RFC #10

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions text/2017-09-04-generalized-scope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Summary

This is a proposal for generalizing the `Scope` struct. It primarily aims to optimize the
`unprotected` function. As a side benefit, we can easily support multiple instances of EBR-managed
region of shared memory.


# Motivation

The `unprotected` function provides a `Scope` without pinning the thread, where the caller thread is
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More precisely (see the Atomic API RFC), the caller thread is either the only one accessing atomics or no one is modifying atomics. This is sort of like a RwLock.

either (1) the only one accessing atomics, or (2) no threads are modifying atomics (think:
reader-writer locks). Assuming this, we can **immediately** deallocate and drop objects in an
unprotected scope. However, even in an unprotected scope, the `defer_free` and `defer_drop`
functions defers freeing and dropping the objects until the scope is over. Even worse, if a lot of
pieces of garbage are created, they are moved to the global garbage queue.

Another motivation is the fact that currently we are supporting only a single instance of
EBR-managed region of shared memory. For example, a bad-behaving mutator can pin itself
indefinitely so that the global epoch cannot be advanced too long. In order to mitigate this
problem, we would like to support multiple instances of EBR so that a mutator in an instance cannot
bother the advancement of another instance's epoch.


# Detailed Design

This proposal is fully implemented
in [this branch](https://github.com/jeehoonkang/crossbeam-epoch/tree/unprotected).


## Generalizing `Scope`

In order to enhance the `unprotected` function, we propose:

- Creating
the
[`Scope` trait](https://github.com/jeehoonkang/crossbeam-epoch/blob/unprotected/src/realm.rs#L15),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of creating a split between EpochScope and UnprotectedScope, why not just put is_unprotected: bool inside Scope?

which provides the methods `Scope` currently has;

- Parameterizing `&'scope Scope` in lots of methods in `atomic.rs`
with
[`S: Scope<'scope>`](https://github.com/jeehoonkang/crossbeam-epoch/blob/unprotected/src/atomic.rs#L209);

- Renaming the existing `Scope` struct
into
[`EpochScope`](https://github.com/jeehoonkang/crossbeam-epoch/blob/unprotected/src/mutator.rs#L58),
and
[implementing `Scope` for `&EpochScope`](https://github.com/jeehoonkang/crossbeam-epoch/blob/unprotected/src/mutator.rs#L276);
and

- Making an empty
struct
[`UnprotectedScope`](https://github.com/jeehoonkang/crossbeam-epoch/blob/unprotected/src/mutator.rs#L78),
[implementing `Scope` for `UnprotectedScope`](https://github.com/jeehoonkang/crossbeam-epoch/blob/unprotected/src/mutator.rs#L319),
and
[letting `unprotected` use `UnprotectedScope`](https://github.com/jeehoonkang/crossbeam-epoch/blob/unprotected/src/mutator.rs#L200).

In the implementation of `Scope` for `UnprotectedScope`, the `defer*` functions immediately disposes
the garbage, and the `flush` function does nothing.


## Supporting Multiple Realms

In order to support multiple instances of EBR, we propose:

- Creating
[`Realm` trait](https://github.com/jeehoonkang/crossbeam-epoch/blob/unprotected/src/realm.rs#L54),
which represents an instance of EBR and provides the methods to access the mutator registries, the
global queue, and the global epoch;

- Add
a
[`Realm` field](https://github.com/jeehoonkang/crossbeam-epoch/blob/unprotected/src/mutator.rs#L46) to
the `Mutator` struct, which represents the realm it belongs to;

- Making an empty
struct
[`DefaultRealm`](https://github.com/jeehoonkang/crossbeam-epoch/blob/unprotected/src/default.rs#L27),
which implements `Realm` with static objects; and

- Making
the
[`UserRealm`](https://github.com/jeehoonkang/crossbeam-epoch/blob/unprotected/src/realm.rs#L107)
struct,
which
[implements `Realm`](https://github.com/jeehoonkang/crossbeam-epoch/blob/unprotected/src/realm.rs#L131) with
its data.

You can use a custom `UserRealm` as follows:

```rust
use crossbeam_epoch::{Scope, UserRealm, Mutator};

let realm = UserRealm::new();
let mutator = Mutator::new(&realm);
mutator.pin(|scope| {
unsafe {
scope.defer(|| {
println!("hello, world!");
});
}
});
```


# Drawbacks

Its interface is more complicated than before. However, I believe the implementation is clearer than
before. For example, now `Mutator` does not directly depend on the static data defined in
`default.rs` (renaming of
`global.rs`)](https://github.com/crossbeam-rs/crossbeam-epoch/pull/4#discussion_r130319009).
Furthermore, after the [impl Trait](https://github.com/rust-lang/rust/issues/34511) feature is
landed in the Rust compiler, we will no longer need to expose the implementations of `Scope`,
resulting in an interface as simple as that of today.



# Alternatives

Maybe the current interface is good enough.



# Unresolved questions

Is it really useful to use multiple instances of EBR? Is there any practical use cases of multiple
EBR instances?