From 32ae12b3d1062babf4f052db42c649e30b11673a Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Mon, 10 Jul 2017 19:26:11 -0400 Subject: Add LocalKey::try_with as an alternative to state --- src/libstd/thread/local.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'src/libstd/thread') diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index dad21473eae..18979fbbdbe 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -232,6 +232,32 @@ pub enum LocalKeyState { Destroyed, } +/// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with). +#[unstable(feature = "thread_local_state", + reason = "state querying was recently added", + issue = "27716")] +pub struct AccessError { + _private: (), +} + +#[unstable(feature = "thread_local_state", + reason = "state querying was recently added", + issue = "27716")] +impl fmt::Debug for AccessError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("AccessError").finish() + } +} + +#[unstable(feature = "thread_local_state", + reason = "state querying was recently added", + issue = "27716")] +impl fmt::Display for AccessError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt("already destroyed", f) + } +} + impl LocalKey { #[doc(hidden)] #[unstable(feature = "thread_local_internals", @@ -331,6 +357,32 @@ impl LocalKey { } } } + + /// Acquires a reference to the value in this TLS key. + /// + /// This will lazily initialize the value if this thread has not referenced + /// this key yet. If the key has been destroyed (which may happen if this is called + /// in a destructor), this function will return a ThreadLocalError. + /// + /// # Panics + /// + /// This function will still `panic!()` if the key is uninitialized and the + /// key's initializer panics. + #[unstable(feature = "thread_local_state", + reason = "state querying was recently added", + issue = "27716")] + pub fn try_with(&'static self, f: F) -> Result + where F: FnOnce(&T) -> R { + unsafe { + let slot = (self.inner)().ok_or(AccessError { + _private: (), + })?; + Ok(f(match *slot.get() { + Some(ref inner) => inner, + None => self.init(slot), + })) + } + } } #[doc(hidden)] -- cgit 1.4.1-3-g733a5 From 8b5549defb629210a8ffc1af08b3209e084fbfd8 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Tue, 11 Jul 2017 11:04:19 -0400 Subject: Fix @alexcrichton comments --- src/libstd/io/stdio.rs | 22 ++++++++++++++-------- src/libstd/thread/mod.rs | 2 +- src/test/run-pass/tls-try-with.rs | 4 ++++ 3 files changed, 19 insertions(+), 9 deletions(-) (limited to 'src/libstd/thread') diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index d71fa133454..fb489bf487b 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -17,7 +17,7 @@ use io::{self, Initializer, BufReader, LineWriter}; use sync::{Arc, Mutex, MutexGuard}; use sys::stdio; use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; -use thread::LocalKey; +use thread::{LocalKey, LocalKeyState}; /// Stdout used by print! and println! macros thread_local! { @@ -674,14 +674,20 @@ fn print_to(args: fmt::Arguments, local_s: &'static LocalKey>>>, global_s: fn() -> T, label: &str) where T: Write { - let result = local_s.try_with(|s| { - if let Ok(mut borrowed) = s.try_borrow_mut() { - if let Some(w) = borrowed.as_mut() { - return w.write_fmt(args); - } + let result = match local_s.state() { + LocalKeyState::Uninitialized | + LocalKeyState::Destroyed => global_s().write_fmt(args), + LocalKeyState::Valid => { + local_s.with(|s| { + if let Ok(mut borrowed) = s.try_borrow_mut() { + if let Some(w) = borrowed.as_mut() { + return w.write_fmt(args); + } + } + global_s().write_fmt(args) + }) } - global_s().write_fmt(args) - }).unwrap_or_else(|_| global_s().write_fmt(args)); + }; if let Err(e) = result { panic!("failed printing to {}: {}", label, e); } diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index f4fe52ca3b3..07a3a01ce86 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -159,7 +159,7 @@ use time::Duration; #[macro_use] mod local; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::local::{LocalKey, LocalKeyState}; +pub use self::local::{LocalKey, LocalKeyState, AccessError}; // The types used by the thread_local! macro to access TLS keys. Note that there // are two types, the "OS" type and the "fast" type. The OS thread local key diff --git a/src/test/run-pass/tls-try-with.rs b/src/test/run-pass/tls-try-with.rs index 09d7dbd66eb..c072ec0679d 100644 --- a/src/test/run-pass/tls-try-with.rs +++ b/src/test/run-pass/tls-try-with.rs @@ -14,6 +14,8 @@ use std::thread; +static mut DROP_RUN: bool = false; + struct Foo; thread_local!(static FOO: Foo = Foo {}); @@ -21,6 +23,7 @@ thread_local!(static FOO: Foo = Foo {}); impl Drop for Foo { fn drop(&mut self) { assert!(FOO.try_with(|_| panic!("`try_with` closure run")).is_err()); + unsafe { DROP_RUN = true; } } } @@ -30,4 +33,5 @@ fn main() { 132 }).expect("`try_with` failed"), 132); }).join().unwrap(); + assert!(unsafe { DROP_RUN }); } -- cgit 1.4.1-3-g733a5 From a301f84b6afc30c58dede5ddd804890f7a6f20a5 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Wed, 12 Jul 2017 10:55:39 -0600 Subject: Use try_with for with implementation --- src/libstd/thread/local.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'src/libstd/thread') diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 18979fbbdbe..28e8f72ac64 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -284,15 +284,8 @@ impl LocalKey { #[stable(feature = "rust1", since = "1.0.0")] pub fn with(&'static self, f: F) -> R where F: FnOnce(&T) -> R { - unsafe { - let slot = (self.inner)(); - let slot = slot.expect("cannot access a TLS value during or \ - after it is destroyed"); - f(match *slot.get() { - Some(ref inner) => inner, - None => self.init(slot), - }) - } + self.try_with(f).expect("cannot access a TLS value during or \ + after it is destroyed") } unsafe fn init(&self, slot: &UnsafeCell>) -> &T { -- cgit 1.4.1-3-g733a5