De-stabilize thread::scoped and friends
Issue #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]
This commit is contained in:
@@ -274,7 +274,8 @@ impl Builder {
|
|||||||
/// Unlike the `scoped` free function, this method yields an
|
/// Unlike the `scoped` free function, this method yields an
|
||||||
/// `io::Result` to capture any failure to create the thread at
|
/// `io::Result` to capture any failure to create the thread at
|
||||||
/// the OS level.
|
/// 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
|
pub fn scoped<'a, T, F>(self, f: F) -> io::Result<JoinGuard<'a, T>> where
|
||||||
T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
|
T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
|
||||||
{
|
{
|
||||||
@@ -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`
|
/// Panics if the OS fails to create a thread; use `Builder::scoped`
|
||||||
/// to recover from such errors.
|
/// 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
|
pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where
|
||||||
T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
|
T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
|
||||||
{
|
{
|
||||||
@@ -674,7 +676,8 @@ impl Drop for JoinHandle {
|
|||||||
/// handle: the ability to join a child thread is a uniquely-owned
|
/// handle: the ability to join a child thread is a uniquely-owned
|
||||||
/// permission.
|
/// permission.
|
||||||
#[must_use = "thread will be immediately joined if `JoinGuard` is not used"]
|
#[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> {
|
pub struct JoinGuard<'a, T: Send + 'a> {
|
||||||
inner: JoinInner<T>,
|
inner: JoinInner<T>,
|
||||||
_marker: PhantomData<&'a T>,
|
_marker: PhantomData<&'a T>,
|
||||||
@@ -706,7 +709,8 @@ impl<'a, T: Send + 'a> JoinGuard<'a, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe_destructor]
|
#[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> {
|
impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if !self.inner.joined {
|
if !self.inner.joined {
|
||||||
|
|||||||
Reference in New Issue
Block a user