-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Unchecked thread spawning #55043
Unchecked thread spawning #55043
Conversation
moves code for `thread::Builder::spawn` into new public unsafe function `spawn_unchecked` and transforms `spawn` into a safe wrapper.
removes unnecessary `unsafe`, adds `unstable` attribute
sync fork with upstream (master)
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @Kimundi (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
removes trailing whitespaces, replaces TODO with FIXME
I agree this is a reasonable thing to add. But doesn't this need an RFC? It's a new API addition, after all. |
I may have misread the guidelines, but it was may understanding that additions and changes to the stdlib do not necessarily require an RFC. |
Changes for sure do, or at least did... that's what got me my first RFC ;) Additions, not sure. Needs an FCP at least. Cc @rust-lang/libs |
generic lifetime bound `'a` can be inferred.
…ixes remove unnecessary lifetime bounds
@RalfJung This does not require an RFC; signoff / fcp merge on this PR by T-libs is sufficient. (We treat language changes differently than minor libs additions...) |
This PR looks good for me, except for the missing doc, which needs to be added before merging. Could someone initiate an FCP? |
…ixes Unchecked thread spawning fixes
sync with upstream
sync with upstream
I've added the missing documentation. |
@rfcbot fcp merge @rust-lang/libs: we may want an RFC on this because the API being added is pretty fundamental, but I don't really think there's much design space to explore here. This PR adds an This is intended to be used as a building block for other concurrency library that want access to the platform thread spawning mechanism but intend to allow non- To me this API seems like a clear solution to a real problem and consistent with our exposure of other unsafe functions used as building blocks in the std APIs. I don't know what alternative designs would be. I'm not certain if |
Team member @withoutboats has proposed to merge this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
@oliver-giersch oh yeah feel free to file an issue lik @stjepang, and we can fill out the tags and such after-the-fact |
Thanks for the heads-up :) The tracking issue is #55132 |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
The final comment period, with a disposition to merge, as per the review above, is now complete. |
@bors: r+ |
📌 Commit 7849aed has been approved by |
⌛ Testing commit 7849aed with merge 3345cad44c04051079a42fe5d485fcd09037c9fa... |
💔 Test failed - status-appveyor |
@bors: retry |
…excrichton Unchecked thread spawning # Summary Add an unsafe interface for spawning lifetime-unrestricted threads for library authors to build less-contrived, less-hacky safe abstractions on. # Motivation So a few years back scoped threads were entirely removed from the Rust stdlib, the reason being that it was possible to leak the scoped thread's join guards without resorting to unsafe code, which meant the concept was not completely safe, either. Only a maximally-restrictive safe API for thread spawning was kept in the stdlib, that requires `'static` lifetime bounds on both the thread closure and its return type. A number of 3rd party libraries sprung up to offer their implementations for safe scoped threads implementations. These work by essentially hiding the join guards from the user, thus forcing them to join at the end of an (internal) function scope. However, since these libraries have to use the maximally restrictive thread spawning API, they have to resort to some very contrived manipulations and subversions of Rust's type system to basically achieve what this commit does with some minimal restructuring of the current code and exposing a new unsafe function signature for spawning threads without lifetime restrictions. Obviously this is unsafe, but its main use would be to allow library authors to write safe abstractions with and around it. To further illustrate my point, here's a quick summary of the hoops that, for instance `crossbeam`, has to jump through to spawn a lifetime unrestricted thread, all of which would not be necessary if an unsafe API existed as part of the stdlib: 1. Allocate an `Arc<Option<T>>` on the heap where the result with type `T: 'a` will go (in practice requires `Mutex` or `UnsafeCell` as well). 2. Wrap the desired thread closure with lifetime bound `'a` into another closure (also `..: 'a`) that returns `()`, executes the inner closure and writes its result into the pre-allocated `Option<T>`. 3. Box the wrapping closure, cast it to a trait object (`FnBox`) and (unsafely) transmute its lifetime bound from `'a` to `'static`. So while this new `spawn_unchecked` function is certainly not very relevant for general use, since scoped threads are so common I think it makes sense to expose an interface for libraries implementing these to build on. The changes implemented are also very minimal: The current `spawn` function (which internally contains unsafe code) is moved into an unsafe `spawn_unchecked` function, which the safe function then wraps around. # Issues - ~~so far, no documentation for the new function (yet)~~ - the name of the function might be controversial, as `*_unchecked` more commonly indicates that some sort of runtime check is omitted (`unrestricted` may be more fitting) - if accepted, it might make sense to add a freestanding `thread::spawn_unchecked` function similar to the current `thread::spawn` for convenience.
☀️ Test successful - status-appveyor, status-travis |
I have some concerns about the absence of panic safety in the documentation for this. For example take this innocently looking variation of the example listed in the documentation:
In particular, the following events happen:
Some more footguns:
|
Summary
Add an unsafe interface for spawning lifetime-unrestricted threads for
library authors to build less-contrived, less-hacky safe abstractions
on.
Motivation
So a few years back scoped threads were entirely removed from the Rust
stdlib, the reason being that it was possible to leak the scoped thread's
join guards without resorting to unsafe code, which meant the concept
was not completely safe, either.
Only a maximally-restrictive safe API for thread spawning was kept in the
stdlib, that requires
'static
lifetime bounds on both the thread closureand its return type.
A number of 3rd party libraries sprung up to offer their implementations
for safe scoped threads implementations.
These work by essentially hiding the join guards from the user, thus
forcing them to join at the end of an (internal) function scope.
However, since these libraries have to use the maximally restrictive
thread spawning API, they have to resort to some very contrived manipulations
and subversions of Rust's type system to basically achieve what this commit does
with some minimal restructuring of the current code and exposing a new unsafe
function signature for spawning threads without lifetime restrictions.
Obviously this is unsafe, but its main use would be to allow library authors
to write safe abstractions with and around it.
To further illustrate my point, here's a quick summary of the hoops that,
for instance
crossbeam
, has to jump through to spawn a lifetime unrestrictedthread, all of which would not be necessary if an unsafe API existed as part
of the stdlib:
Allocate an
Arc<Option<T>>
on the heap where the result with typeT: 'a
will go (in practice requiresMutex
orUnsafeCell
as well).Wrap the desired thread closure with lifetime bound
'a
into anotherclosure (also
..: 'a
) that returns()
, executes the inner closure andwrites its result into the pre-allocated
Option<T>
.Box the wrapping closure, cast it to a trait object (
FnBox
) and(unsafely) transmute its lifetime bound from
'a
to'static
.So while this new
spawn_unchecked
function is certainly not very relevantfor general use, since scoped threads are so common I think it makes sense
to expose an interface for libraries implementing these to build on.
The changes implemented are also very minimal: The current
spawn
function(which internally contains unsafe code) is moved into an unsafe
spawn_unchecked
function, which the safe function then wraps around.
Issues
so far, no documentation for the new function (yet)*_unchecked
more commonlyindicates that some sort of runtime check is omitted (
unrestricted
may bemore fitting)
thread::spawn_unchecked
function similar to the current
thread::spawn
for convenience.