-
Notifications
You must be signed in to change notification settings - Fork 7
Conversation
Closes #25
Ah, good point. Maybe we should make it |
/// It should not be called in another TLS storage's `drop()`, because `HANDLE` may already be | ||
/// droped. | ||
pub unsafe fn default_handle() -> &'static Handle { | ||
&*HANDLE.with(|handle| handle as *const _) |
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.
The documentation for with
is a bit ambiguous, but looking at the source it should always panic if the key has been destroyed. Since we return a reference, it can't escape its scope and so HANDLE
won't be destroyed while it exists. Hence, this seems safe (but I could be wrong of course).
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 unsafe because this function allows you to obtain a &'static Handle
reference and then use it even after HANDLE
gets destroyed, without any additional checks.
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.
@Vtec234 Destruction in the context of TLS is somewhat different than destruction in the rest of Rust unfortunately. When a thread exits, all of the registered TLS variables get destroyed - it doesn't have to do with scope. The problem arises when the Drop
implementation for a TLS variable accesses another TLS variable which has already been dropped. @ezrosent and I have run into this issue, for example, when our own allocator caches (stored in TLS) were dropped after Crossbeam's TLS was dropped, but we relied on Crossbeam in order to implement Drop
.
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.
In that case another option would be to forward with
and expose something like with_default_handle<F: FnOnce(&Handle) -> R>(f: F) -> R
.
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.
That's true, but that might lead to callback spaghetti. It's just as easy to do default_handle() -> Option<&Handle>
, and somewhat more ergonomic.
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.
And what's the issue with lifetimes when returning Option<&Handle>
? Or is the lifetime problem only an issue when returning Option<Handle>
(ie, not a reference)?
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.
@joshlf: Without a lifetime-binding argument (like in with
) the lifetime of &Handle
will have to be 'static
, and that can in turn be leaked until after the TLS drops since Rust allows passing 'static
references around freely.
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.
Ah I see. Fair enough.
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.
A problem with fn default_handle() -> Option<&Handle>
is we cannot implement it in Rust stable. I think we need to use HANDLE.try_with()
, which is provided only in Rust nightly.
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.
Ah good point. Would you guys be cool with just having it be feature-gated on nightly?
What's the benefit of having a thread_local! { pub static HANDLE: Handle = COLLECTOR.handle(); } |
@stjepang IMO, exposing |
Closing (in favor of #31) |
Closes #25
default_handle()
is unsafe because when it is called in another TLS object'sdrop()
,HANDLE
may have already been dropped.