about summary refs log tree commit diff
path: root/src/libstd/io
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-11-14 14:20:57 -0800
committerAlex Crichton <alex@alexcrichton.com>2014-11-23 23:37:16 -0800
commita9c1152c4bf72132806cb76045b3464d59db07da (patch)
tree89ba92d5f5788e3323b75ca003bf74661a94e4de /src/libstd/io
parent4e5259503cd8aac9905c7ac6d68d0c4caab1d28c (diff)
downloadrust-a9c1152c4bf72132806cb76045b3464d59db07da.tar.gz
rust-a9c1152c4bf72132806cb76045b3464d59db07da.zip
std: Add a new top-level thread_local module
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]: https://github.com/rust-lang/rfcs/pull/461
[breaking-change]
Diffstat (limited to 'src/libstd/io')
-rw-r--r--src/libstd/io/stdio.rs31
1 files changed, 23 insertions, 8 deletions
diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs
index 7374668a69d..d450e9f1dce 100644
--- a/src/libstd/io/stdio.rs
+++ b/src/libstd/io/stdio.rs
@@ -29,22 +29,24 @@ out.write(b"Hello, world!");
 
 use self::StdSource::*;
 
-use failure::local_stderr;
+use boxed::Box;
+use cell::RefCell;
+use failure::LOCAL_STDERR;
 use fmt;
 use io::{Reader, Writer, IoResult, IoError, OtherIoError,
          standard_error, EndOfFile, LineBufferedWriter, BufferedReader};
 use iter::Iterator;
 use kinds::Send;
 use libc;
+use mem;
 use option::{Option, Some, None};
-use boxed::Box;
-use sys::{fs, tty};
 use result::{Ok, Err};
 use rustrt;
 use rustrt::local::Local;
 use rustrt::task::Task;
 use slice::SlicePrelude;
 use str::StrPrelude;
+use sys::{fs, tty};
 use uint;
 
 // And so begins the tale of acquiring a uv handle to a stdio stream on all
@@ -87,7 +89,9 @@ fn src<T>(fd: libc::c_int, _readable: bool, f: |StdSource| -> T) -> T {
     }
 }
 
-local_data_key!(local_stdout: Box<Writer + Send>)
+thread_local!(static LOCAL_STDOUT: RefCell<Option<Box<Writer + Send>>> = {
+    RefCell::new(None)
+})
 
 /// Creates a new non-blocking handle to the stdin of the current process.
 ///
@@ -167,7 +171,10 @@ pub fn stderr_raw() -> StdWriter {
 /// Note that this does not need to be called for all new tasks; the default
 /// output handle is to the process's stdout stream.
 pub fn set_stdout(stdout: Box<Writer + Send>) -> Option<Box<Writer + Send>> {
-    local_stdout.replace(Some(stdout)).and_then(|mut s| {
+    let mut new = Some(stdout);
+    LOCAL_STDOUT.with(|slot| {
+        mem::replace(&mut *slot.borrow_mut(), new.take())
+    }).and_then(|mut s| {
         let _ = s.flush();
         Some(s)
     })
@@ -182,7 +189,10 @@ pub fn set_stdout(stdout: Box<Writer + Send>) -> Option<Box<Writer + Send>> {
 /// Note that this does not need to be called for all new tasks; the default
 /// output handle is to the process's stderr stream.
 pub fn set_stderr(stderr: Box<Writer + Send>) -> Option<Box<Writer + Send>> {
-    local_stderr.replace(Some(stderr)).and_then(|mut s| {
+    let mut new = Some(stderr);
+    LOCAL_STDERR.with(|slot| {
+        mem::replace(&mut *slot.borrow_mut(), new.take())
+    }).and_then(|mut s| {
         let _ = s.flush();
         Some(s)
     })
@@ -200,11 +210,16 @@ pub fn set_stderr(stderr: Box<Writer + Send>) -> Option<Box<Writer + Send>> {
 //  })
 fn with_task_stdout(f: |&mut Writer| -> IoResult<()>) {
     let result = if Local::exists(None::<Task>) {
-        let mut my_stdout = local_stdout.replace(None).unwrap_or_else(|| {
+        let mut my_stdout = LOCAL_STDOUT.with(|slot| {
+            slot.borrow_mut().take()
+        }).unwrap_or_else(|| {
             box stdout() as Box<Writer + Send>
         });
         let result = f(&mut *my_stdout);
-        local_stdout.replace(Some(my_stdout));
+        let mut var = Some(my_stdout);
+        LOCAL_STDOUT.with(|slot| {
+            *slot.borrow_mut() = var.take();
+        });
         result
     } else {
         let mut io = rustrt::Stdout;