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

Global resource handling #3

Open
jethrogb opened this issue Mar 7, 2018 · 10 comments
Open

Global resource handling #3

jethrogb opened this issue Mar 7, 2018 · 10 comments

Comments

@jethrogb
Copy link
Collaborator

jethrogb commented Mar 7, 2018

Often, global decisions affecting the entire dependency tree need to be made.
Current examples of this in std are panic behavior and the global allocator.
Outside of std there are logging and event loops, standard RNG.

This issue proposes to come up with a generic system that works for all such cases.

@Ericson2314
Copy link
Collaborator

The perfect general solution need be ML modules, or something else that's just as big a change. But there is a more incremental solution on top of rust-lang/rust#27389 . Basically the pattern there is there is some ZST which implements a trait by calling the methods on the user-defined static. We could replace #![global_allocator] with #![global(MyTrait)] to expose that pattern in its full generality.

@jethrogb
Copy link
Collaborator Author

@aturon In our meeting you mentioned event loops are a global resource. Why? If you are currently a task running on an event loop, you should be able to figure that out somehow (e.g. Task::current()). If you are not currently on an event loop, you're probably in charge of instantiating it.

@jethrogb
Copy link
Collaborator Author

@jethrogb
Copy link
Collaborator Author

jethrogb commented Mar 18, 2018

Missing from the current allocator API design is a good way to hook into the selected global singleton. There's a lot of compiler magic to make it work for what's tagged #[global_allocator], including adding global functions that just forward to the calling the trait methods on the singleton. However, this is only done if you explicitly choose a global allocator, and not when using the standard allocator.

See https://github.com/rust-lang/rust/blob/master/src/librustc_allocator/expand.rs and https://github.com/rust-lang/rust/blob/master/src/librustc/middle/allocator.rs

I guess the only way to do this kind of dependency inversion in Rust today is with a extern { fn } kludge.

@jethrogb
Copy link
Collaborator Author

How about leveraging extern statics?

// liballoc
pub mod allocator {
  pub unsafe trait Alloc { /* ... */ }
}

pub mod heap {
  extern {
    #[global="allocator"]
    static HEAP: impl ::allocator:Alloc;
  }
}
// liballoc_system
use alloc::allocator::Alloc;

struct System;

impl Alloc for System { /* ... */ }

#[global="allocator"]
static SYSTEM_ALLOCATOR: System = System;

@pierzchalski
Copy link
Collaborator

Is there an issue using existing/"boring" extern statics? Eg.

pub mod heap {
  extern {
    // Static trait object because an anonymous `impl` type can't be simply linked
    static HEAP_IMPL: &::allocator::Alloc;
  }
}
#[no_mangle]
static HEAP_IMPL: &Alloc = &System;

Naively this looks like it would have some runtime overhead from the vtable, but... it's static? I would hope it would be eligible for inlining or LTO or whatever. Not sure if we can do good error reporting if someone includes two global allocators, though.

@jethrogb
Copy link
Collaborator Author

jethrogb commented Apr 3, 2018

I guess that's possible. I'm not a big fan because:

  1. Accessing normal extern statics is unsafe.
  2. Normal extern statics are subject to the improper_ctypes lint.
  3. Dynamic dispatch. LTO might pick it up but I'm not sure.
  4. Having the linker do collision detection is not very user-friendly

@pierzchalski
Copy link
Collaborator

Yeah, fair enough. What's your vision on how the compiler should see an extern static X: impl Y? That's spiritually the kind of existential type that an ML-style module system would provide, it's just being filled via a magic global name instead of module inheritance.

@Ericson2314
Copy link
Collaborator

rust-lang/rfcs#2492 is an RFC for this.

@Ericson2314
Copy link
Collaborator

(@pitdicker I'm sorry to say I didn't include the rand example is it already does a decent job by spliting the create into two with a trait, but yes we could overhaul the thing such that the core trait has both OsRng and ThreadRng as extern existential types, and then each OS's implementation has its own crate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants