-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
RFC: Add a thread local storage module, std::tls #461
Conversation
Introduce a new thread local storage module to the standard library, `std::tls`, providing: * Scoped TLS, a non-owning variant of TLS for any value. * Owning TLS, an owning, dynamically initialized, dynamically destructed variant, similar to `std::local_data` today.
lost when writing Unix-only code. | ||
|
||
Destructor support for Windows will be provided through a custom implementation | ||
of tracking known destructors for TLS keys. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On Windows, you can set a callback for when a thread exits, and you can then iterate over all TLS keys and destroy them if they are set.
See https://github.com/ChromiumWebApps/chromium/blob/master/base/threading/thread_local_storage_win.cc#L42 for how to do it without using DllMain.
Iterating over all possible TLS keys is quadratic instead of linear if they are sparsely used, but it should be possible to write code that directly accesses the Windows TEB to avoid this if desired.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed! I ran across that same trick when whipping up the sample implementation. I definitely agree that the implementation can be improved as well!
cc @thestinger, would be good to get your feedback on this proposal. |
|
||
### Destructor support | ||
|
||
The major difference between Unix and Windows TLS support is that Unix supports |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's also possible to use only #[thread_local]
with no secondary pthread_key_create
/ synchronization by using C++11 destructor support. On Linux, glibc defines a fn __cxa_thread_atexit_impl(dtor: unsafe extern "C" fn(ptr: *mut c_void), ptr: *mut c_void, dso_symbol: *mut i8)
where dso_symbol
can just be retrived by defining static mut __dso_handle: i8
. On OS X, there's a fn _tlv_atexit(dtor: unsafe extern "C" fn(ptr: *mut c_void), ptr: *mut c_void);
function. Rust could use the weak symbol trick to call these when available and fall back to a crappier implementation on top of dynamic TLS.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed! If you take a look at the sample implementation you'll see that it does precisely that!
ISTM like scoped TLS may be the 'preferred' way to use TLS as it is more structured, harder to create error-prone access patterns, but this design gives traditional tls the better module name. |
This RFC doesn't seem to explain how it achieves acceptable performance compared to |
@brson that's a good point about naming, we could take no preference at all and perhaps move everything in to The sample implementation's benchmarking numbers are currently all on par with Today I also discovered an unsoundness with this API as proposed, specifically with the #![feature(phase)]
#[phase(plugin, link)]
extern crate tls;
use std::cell::RefCell;
dynamic_tls!(static FOO: Box<int> = box 1)
dynamic_tls!(static BAR: RefCell<Option<tls::dynamic::Ref<Box<int>>>> = RefCell::new(None))
fn main() {
*BAR.get().unwrap().borrow_mut() = Some(FOO.get().unwrap());
} What this really wants to do is to store a |
When I hear TLS I think "Transport Layer Security", not "Thread Local Storage". Wouldn't it make more sense to call this |
@alexcrichton Could struct ThreadRef<T> {
marker: NoSend,
data: &'static T
} and the appropriate Deref impls? |
@reem I thought so! (and I was really hoping so). The catch is that the |
This PR completes the removal of the runtime system and green-threaded abstractions as part of implementing [RFC 230](rust-lang/rfcs#230). Specifically: * It removes the `Runtime` trait, welding the scheduling infrastructure directly to native threads. * It removes `libgreen` and `libnative` entirely. * It rewrites `sync::mutex` as a trivial layer on top of native mutexes. Eventually, the two modules will be merged. * It hides the vast majority of `std::rt`. This completes the basic task of removing the runtime system (I/O and scheduling) and components that depend on it. After this lands, a follow-up PR will pull the `rustrt` crate back into `std`, turn `std::task` into `std::thread` (with API changes to go along with it), and completely cut out the remaining startup/teardown sequence. Other changes, including new [TLS](rust-lang/rfcs#461) and synchronization are in the RFC or pre-RFC phase. Closes #17325 Closes #18687 [breaking-change] r? @alexcrichton
RFC accepted. |
@alexcrichton it looks like the simplest solution would just be to add a |
This commit removes the `std::local_data` module in favor of a new `std::thread_local` module providing thread local storage. The module provides two variants of TLS: one which owns its contents and one which is based on scoped references. Each implementation has pros and cons listed in the documentation. Both flavors have accessors through a function called `with` which yield a reference to a closure provided. Both flavors also panic if a reference cannot be yielded and provide a function to test whether an access would panic or not. This is an implementation of [RFC 461][rfc] and full details can be found in that RFC. This is a breaking change due to the removal of the `std::local_data` module. All users can migrate to the new thread local system like so: thread_local!(static FOO: Rc<RefCell<Option<T>>> = Rc::new(RefCell::new(None))) The old `local_data` module inherently contained the `Rc<RefCell<Option<T>>>` as an implementation detail which must now be explicitly stated by users. [rfc]: rust-lang/rfcs#461 [breaking-change]
This commit removes the `std::local_data` module in favor of a new `std::thread_local` module providing thread local storage. The module provides two variants of TLS: one which owns its contents and one which is based on scoped references. Each implementation has pros and cons listed in the documentation. Both flavors have accessors through a function called `with` which yield a reference to a closure provided. Both flavors also panic if a reference cannot be yielded and provide a function to test whether an access would panic or not. This is an implementation of [RFC 461][rfc] and full details can be found in that RFC. This is a breaking change due to the removal of the `std::local_data` module. All users can migrate to the new tls system like so: thread_local!(static FOO: Rc<RefCell<Option<T>>> = Rc::new(RefCell::new(None))) The old `local_data` module inherently contained the `Rc<RefCell<Option<T>>>` as an implementation detail which must now be explicitly stated by users. [rfc]: rust-lang/rfcs#461 [breaking-change]
This commit removes the `std::local_data` module in favor of a new `std::thread_local` module providing thread local storage. The module provides two variants of TLS: one which owns its contents and one which is based on scoped references. Each implementation has pros and cons listed in the documentation. Both flavors have accessors through a function called `with` which yield a reference to a closure provided. Both flavors also panic if a reference cannot be yielded and provide a function to test whether an access would panic or not. This is an implementation of [RFC 461][rfc] and full details can be found in that RFC. This is a breaking change due to the removal of the `std::local_data` module. All users can migrate to the new thread local system like so: thread_local!(static FOO: Rc<RefCell<Option<T>>> = Rc::new(RefCell::new(None))) The old `local_data` module inherently contained the `Rc<RefCell<Option<T>>>` as an implementation detail which must now be explicitly stated by users. [rfc]: rust-lang/rfcs#461 [breaking-change]
This commit removes the `std::local_data` module in favor of a new `std::thread_local` module providing thread local storage. The module provides two variants of TLS: one which owns its contents and one which is based on scoped references. Each implementation has pros and cons listed in the documentation. Both flavors have accessors through a function called `with` which yield a reference to a closure provided. Both flavors also panic if a reference cannot be yielded and provide a function to test whether an access would panic or not. This is an implementation of [RFC 461][rfc] and full details can be found in that RFC. This is a breaking change due to the removal of the `std::local_data` module. All users can migrate to the new tls system like so: thread_local!(static FOO: Rc<RefCell<Option<T>>> = Rc::new(RefCell::new(None))) The old `local_data` module inherently contained the `Rc<RefCell<Option<T>>>` as an implementation detail which must now be explicitly stated by users. [rfc]: rust-lang/rfcs#461 [breaking-change]
This commit removes the `std::local_data` module in favor of a new `std::thread_local` module providing thread local storage. The module provides two variants of TLS: one which owns its contents and one which is based on scoped references. Each implementation has pros and cons listed in the documentation. Both flavors have accessors through a function called `with` which yield a reference to a closure provided. Both flavors also panic if a reference cannot be yielded and provide a function to test whether an access would panic or not. This is an implementation of [RFC 461][rfc] and full details can be found in that RFC. This is a breaking change due to the removal of the `std::local_data` module. All users can migrate to the new thread local system like so: thread_local!(static FOO: Rc<RefCell<Option<T>>> = Rc::new(RefCell::new(None))) The old `local_data` module inherently contained the `Rc<RefCell<Option<T>>>` as an implementation detail which must now be explicitly stated by users. [rfc]: rust-lang/rfcs#461 [breaking-change]
This commit removes the `std::local_data` module in favor of a new `std::thread_local` module providing thread local storage. The module provides two variants of TLS: one which owns its contents and one which is based on scoped references. Each implementation has pros and cons listed in the documentation. Both flavors have accessors through a function called `with` which yield a reference to a closure provided. Both flavors also panic if a reference cannot be yielded and provide a function to test whether an access would panic or not. This is an implementation of [RFC 461][rfc] and full details can be found in that RFC. This is a breaking change due to the removal of the `std::local_data` module. All users can migrate to the new tls system like so: thread_local!(static FOO: Rc<RefCell<Option<T>>> = Rc::new(RefCell::new(None))) The old `local_data` module inherently contained the `Rc<RefCell<Option<T>>>` as an implementation detail which must now be explicitly stated by users. [rfc]: rust-lang/rfcs#461 [breaking-change]
This commit removes the `std::local_data` module in favor of a new `std::thread_local` module providing thread local storage. The module provides two variants of TLS: one which owns its contents and one which is based on scoped references. Each implementation has pros and cons listed in the documentation. Both flavors have accessors through a function called `with` which yield a reference to a closure provided. Both flavors also panic if a reference cannot be yielded and provide a function to test whether an access would panic or not. This is an implementation of [RFC 461][rfc] and full details can be found in that RFC. This is a breaking change due to the removal of the `std::local_data` module. All users can migrate to the new thread local system like so: thread_local!(static FOO: Rc<RefCell<Option<T>>> = Rc::new(RefCell::new(None))) The old `local_data` module inherently contained the `Rc<RefCell<Option<T>>>` as an implementation detail which must now be explicitly stated by users. [rfc]: rust-lang/rfcs#461 [breaking-change]
Introduce a new thread local storage module to the standard library,
std::tls
,providing:
variant, similar to
std::local_data
today.Rendered