diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2014-11-14 14:20:57 -0800 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2014-11-23 23:37:16 -0800 |
| commit | a9c1152c4bf72132806cb76045b3464d59db07da (patch) | |
| tree | 89ba92d5f5788e3323b75ca003bf74661a94e4de /src/libstd/io | |
| parent | 4e5259503cd8aac9905c7ac6d68d0c4caab1d28c (diff) | |
| download | rust-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.rs | 31 |
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; |
