Skip to content

Commit

Permalink
De-stabilize thread::scoped and friends
Browse files Browse the repository at this point in the history
Issue rust-lang#24292 demonstrates that the `scoped` API as currently offered can
be memory-unsafe: the `JoinGuard` can be moved into a context that will
fail to execute destructors prior to the stack frame being popped (for
example, by creating an `Rc` cycle).

This commit reverts the APIs to `unstable` status while a long-term
solution is worked out.

(There are several possible ways to address this issue; it's not a
fundamental problem with the `scoped` idea, but rather an indication
that Rust doesn't currently provide a good way to ensure that
destructors are run within a particular stack frame.)

[breaking-change]
  • Loading branch information
aturon committed Apr 13, 2015
1 parent 588d37c commit 6399bb4
Showing 1 changed file with 8 additions and 4 deletions.
12 changes: 8 additions & 4 deletions src/libstd/thread/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,8 @@ impl Builder {
/// Unlike the `scoped` free function, this method yields an
/// `io::Result` to capture any failure to create the thread at
/// the OS level.
#[stable(feature = "rust1", since = "1.0.0")]
#[unstable(feature = "scoped",
reason = "memory unsafe if destructor is avoided, see #24292")]
pub fn scoped<'a, T, F>(self, f: F) -> io::Result<JoinGuard<'a, T>> where
T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
{
Expand Down Expand Up @@ -387,7 +388,8 @@ pub fn spawn<F>(f: F) -> JoinHandle where F: FnOnce(), F: Send + 'static {
///
/// Panics if the OS fails to create a thread; use `Builder::scoped`
/// to recover from such errors.
#[stable(feature = "rust1", since = "1.0.0")]
#[unstable(feature = "scoped",
reason = "memory unsafe if destructor is avoided, see #24292")]
pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where
T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
{
Expand Down Expand Up @@ -674,7 +676,8 @@ impl Drop for JoinHandle {
/// handle: the ability to join a child thread is a uniquely-owned
/// permission.
#[must_use = "thread will be immediately joined if `JoinGuard` is not used"]
#[stable(feature = "rust1", since = "1.0.0")]
#[unstable(feature = "scoped",
reason = "memory unsafe if destructor is avoided, see #24292")]
pub struct JoinGuard<'a, T: Send + 'a> {
inner: JoinInner<T>,
_marker: PhantomData<&'a T>,
Expand Down Expand Up @@ -706,7 +709,8 @@ impl<'a, T: Send + 'a> JoinGuard<'a, T> {
}

#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
#[unstable(feature = "scoped",
reason = "memory unsafe if destructor is avoided, see #24292")]
impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> {
fn drop(&mut self) {
if !self.inner.joined {
Expand Down

0 comments on commit 6399bb4

Please sign in to comment.