From 4156bc44176d93296a0f1834690dd9792390cec6 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 20 Nov 2014 18:26:47 -0800 Subject: sys: reveal std::io representation to sys module This commit adds a `AsInner` trait to `sys_common` and provides implementations on many `std::io` types. This is a building block for exposing platform-specific APIs that hook into `std::io` types. --- src/libstd/sys/windows/pipe.rs | 10 +++++++++- src/libstd/sys/windows/process.rs | 6 +++--- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'src/libstd/sys/windows') diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index a623c2cd8e2..60bd2b1370f 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -329,7 +329,7 @@ impl UnixStream { } } - fn handle(&self) -> libc::HANDLE { self.inner.handle } + pub fn handle(&self) -> libc::HANDLE { self.inner.handle } fn read_closed(&self) -> bool { self.inner.read_closed.load(atomic::SeqCst) @@ -585,6 +585,10 @@ impl UnixListener { }), }) } + + pub fn handle(&self) -> libc::HANDLE { + self.handle + } } impl Drop for UnixListener { @@ -729,6 +733,10 @@ impl UnixAcceptor { Ok(()) } } + + pub fn handle(&self) -> libc::HANDLE { + self.event.ref0 + } } impl Clone for UnixAcceptor { diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 3fb5ee34356..eddb89c673d 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -26,7 +26,7 @@ use sys::fs; use sys::{mod, retry, c, wouldblock, set_nonblocking, ms_to_timeval, timer}; use sys::fs::FileDesc; use sys_common::helper_thread::Helper; -use sys_common::{AsFileDesc, mkerr_libc, timeout}; +use sys_common::{AsInner, mkerr_libc, timeout}; use io::fs::PathExtensions; use string::String; @@ -105,7 +105,7 @@ impl Process { pub fn spawn(cfg: &C, in_fd: Option

, out_fd: Option

, err_fd: Option

) -> IoResult - where C: ProcessConfig, P: AsFileDesc, + where C: ProcessConfig, P: AsInner, K: BytesContainer + Eq + Hash, V: BytesContainer { use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO}; @@ -195,7 +195,7 @@ impl Process { } } Some(ref fd) => { - let orig = get_osfhandle(fd.as_fd().fd()) as HANDLE; + let orig = get_osfhandle(fd.as_inner().fd()) as HANDLE; if orig == INVALID_HANDLE_VALUE { return Err(super::last_error()) } -- cgit 1.4.1-3-g733a5 From 1e661642105a1033f1c155ceb1b2335dd11cb40a Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 20 Nov 2014 18:30:46 -0800 Subject: libs: add std::os::windows module The new `std::os::windows` module exposes several extension traits for extracting file descriptors, sockets, and handles from `std::io` types. --- src/libstd/os.rs | 5 +++ src/libstd/sys/windows/ext.rs | 100 +++++++++++++++++++++++++++++++++++++++++ src/libstd/sys/windows/mod.rs | 1 + src/libstd/sys/windows/pipe.rs | 2 +- 4 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/libstd/sys/windows/ext.rs (limited to 'src/libstd/sys/windows') diff --git a/src/libstd/os.rs b/src/libstd/os.rs index d7ba4877086..2ba03ac5d60 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -62,6 +62,11 @@ use vec::Vec; #[cfg(unix)] use c_str::ToCStr; #[cfg(unix)] use libc::c_char; +#[cfg(unix)] +pub use sys::ext as unix; +#[cfg(windows)] +pub use sys::ext as windows; + /// Get the number of cores available pub fn num_cpus() -> uint { unsafe { diff --git a/src/libstd/sys/windows/ext.rs b/src/libstd/sys/windows/ext.rs new file mode 100644 index 00000000000..2c58ee69e8b --- /dev/null +++ b/src/libstd/sys/windows/ext.rs @@ -0,0 +1,100 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Experimental extensions to `std` for Windows. +//! +//! For now, this module is limited to extracting handles, file +//! descriptors, and sockets, but its functionality will grow over +//! time. + +#![experimental] + +use sys_common::AsInner; +use libc; + +use io; + +/// Raw HANDLEs. +pub type Handle = libc::HANDLE; + +/// Raw SOCKETs. +pub type Socket = libc::SOCKET; + +/// Extract raw handles. +pub trait AsRawHandle { + /// Extract the raw handle, without taking any ownership. + fn as_raw_handle(&self) -> Handle; +} + +impl AsRawHandle for io::fs::File { + fn as_raw_handle(&self) -> Handle { + self.as_inner().handle() + } +} + +impl AsRawHandle for io::pipe::PipeStream { + fn as_raw_handle(&self) -> Handle { + self.as_inner().handle() + } +} + +impl AsRawHandle for io::net::pipe::UnixStream { + fn as_raw_handle(&self) -> Handle { + self.as_inner().handle() + } +} + +impl AsRawHandle for io::net::pipe::UnixListener { + fn as_raw_handle(&self) -> Handle { + self.as_inner().handle() + } +} + +impl AsRawHandle for io::net::pipe::UnixAcceptor { + fn as_raw_handle(&self) -> Handle { + self.as_inner().handle() + } +} + +/// Extract raw sockets. +pub trait AsRawSocket { + fn as_raw_socket(&self) -> Socket; +} + +impl AsRawSocket for io::net::tcp::TcpStream { + fn as_raw_socket(&self) -> Socket { + self.as_inner().fd() + } +} + +impl AsRawSocket for io::net::tcp::TcpListener { + fn as_raw_socket(&self) -> Socket { + self.as_inner().fd() + } +} + +impl AsRawSocket for io::net::tcp::TcpAcceptor { + fn as_raw_socket(&self) -> Socket { + self.as_inner().fd() + } +} + +impl AsRawSocket for io::net::udp::UdpSocket { + fn as_raw_socket(&self) -> Socket { + self.as_inner().fd() + } +} + +/// A prelude for conveniently writing platform-specific code. +/// +/// Includes all extension traits, and some important type definitions. +pub mod prelude { + pub use super::{Socket, Handle, AsRawSocket, AsRawHandle}; +} diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 815ace21f87..33e7094612e 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -34,6 +34,7 @@ macro_rules! helper_init( (static $name:ident: Helper<$m:ty>) => ( ) ) pub mod c; +pub mod ext; pub mod fs; pub mod os; pub mod tcp; diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index 60bd2b1370f..ca7985aa35b 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -735,7 +735,7 @@ impl UnixAcceptor { } pub fn handle(&self) -> libc::HANDLE { - self.event.ref0 + self.listener.handle() } } -- cgit 1.4.1-3-g733a5 From a9c1152c4bf72132806cb76045b3464d59db07da Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 14 Nov 2014 14:20:57 -0800 Subject: 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>> = Rc::new(RefCell::new(None))) The old `local_data` module inherently contained the `Rc>>` as an implementation detail which must now be explicitly stated by users. [rfc]: https://github.com/rust-lang/rfcs/pull/461 [breaking-change] --- src/liblog/lib.rs | 19 +- src/librustc/util/common.rs | 13 +- src/librustc_trans/trans/base.rs | 35 +- src/librustdoc/html/format.rs | 26 +- src/librustdoc/html/markdown.rs | 55 +- src/librustdoc/html/render.rs | 45 +- src/librustdoc/lib.rs | 17 +- src/librustdoc/markdown.rs | 2 +- src/librustdoc/passes.rs | 4 +- src/librustdoc/stability_summary.rs | 4 +- src/librustrt/lib.rs | 1 - src/librustrt/local_data.rs | 696 --------------------- src/librustrt/task.rs | 64 +- src/libstd/collections/hash/map.rs | 133 ++-- src/libstd/failure.rs | 15 +- src/libstd/io/stdio.rs | 31 +- src/libstd/lib.rs | 31 +- src/libstd/macros.rs | 22 - src/libstd/rand/mod.rs | 31 +- src/libstd/sync/future.rs | 24 - src/libstd/sys/common/mod.rs | 1 + src/libstd/sys/common/thread_local.rs | 306 +++++++++ src/libstd/sys/unix/mod.rs | 7 +- src/libstd/sys/unix/thread_local.rs | 52 ++ src/libstd/sys/windows/mod.rs | 7 +- src/libstd/sys/windows/thread_local.rs | 238 +++++++ src/libstd/thread_local/mod.rs | 634 +++++++++++++++++++ src/libstd/thread_local/scoped.rs | 261 ++++++++ src/libsyntax/attr.rs | 20 +- src/libsyntax/diagnostics/plugin.rs | 32 +- src/libsyntax/ext/mtwt.rs | 28 +- src/libsyntax/parse/token.rs | 13 +- .../plugin_crate_outlive_expansion_phase.rs | 5 +- src/test/compile-fail/core-tls-store-pointer.rs | 16 - src/test/compile-fail/macro-local-data-key-priv.rs | 4 +- src/test/run-pass/macro-local-data-key.rs | 26 - src/test/run-pass/panic-during-tld-destroy.rs | 33 - src/test/run-pass/running-with-no-runtime.rs | 8 - 38 files changed, 1809 insertions(+), 1150 deletions(-) delete mode 100644 src/librustrt/local_data.rs create mode 100644 src/libstd/sys/common/thread_local.rs create mode 100644 src/libstd/sys/unix/thread_local.rs create mode 100644 src/libstd/sys/windows/thread_local.rs create mode 100644 src/libstd/thread_local/mod.rs create mode 100644 src/libstd/thread_local/scoped.rs delete mode 100644 src/test/compile-fail/core-tls-store-pointer.rs delete mode 100644 src/test/run-pass/macro-local-data-key.rs delete mode 100644 src/test/run-pass/panic-during-tld-destroy.rs (limited to 'src/libstd/sys/windows') diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index fd2d97d4deb..dab033e0972 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -171,7 +171,7 @@ extern crate regex; -use regex::Regex; +use std::cell::RefCell; use std::fmt; use std::io::LineBufferedWriter; use std::io; @@ -181,6 +181,8 @@ use std::rt; use std::slice; use std::sync::{Once, ONCE_INIT}; +use regex::Regex; + use directive::LOG_LEVEL_NAMES; pub mod macros; @@ -213,7 +215,9 @@ pub const WARN: u32 = 2; /// Error log level pub const ERROR: u32 = 1; -local_data_key!(local_logger: Box) +thread_local!(static LOCAL_LOGGER: RefCell>> = { + RefCell::new(None) +}) /// A trait used to represent an interface to a task-local logger. Each task /// can have its own custom logger which can respond to logging messages @@ -283,7 +287,9 @@ pub fn log(level: u32, loc: &'static LogLocation, args: &fmt::Arguments) { // Completely remove the local logger from TLS in case anyone attempts to // frob the slot while we're doing the logging. This will destroy any logger // set during logging. - let mut logger = local_logger.replace(None).unwrap_or_else(|| { + let mut logger = LOCAL_LOGGER.with(|s| { + s.borrow_mut().take() + }).unwrap_or_else(|| { box DefaultLogger { handle: io::stderr() } as Box }); logger.log(&LogRecord { @@ -293,7 +299,7 @@ pub fn log(level: u32, loc: &'static LogLocation, args: &fmt::Arguments) { module_path: loc.module_path, line: loc.line, }); - local_logger.replace(Some(logger)); + set_logger(logger); } /// Getter for the global log level. This is a function so that it can be called @@ -305,7 +311,10 @@ pub fn log_level() -> u32 { unsafe { LOG_LEVEL } } /// Replaces the task-local logger with the specified logger, returning the old /// logger. pub fn set_logger(logger: Box) -> Option> { - local_logger.replace(Some(logger)) + let mut l = Some(logger); + LOCAL_LOGGER.with(|slot| { + mem::replace(&mut *slot.borrow_mut(), l.take()) + }) } /// A LogRecord is created by the logging macros, and passed as the only diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index e2fa02584f4..7973004d515 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -10,7 +10,7 @@ #![allow(non_camel_case_types)] -use std::cell::RefCell; +use std::cell::{RefCell, Cell}; use std::collections::HashMap; use std::fmt::Show; use std::hash::{Hash, Hasher}; @@ -26,11 +26,14 @@ use syntax::visit::Visitor; pub struct ErrorReported; pub fn time(do_it: bool, what: &str, u: U, f: |U| -> T) -> T { - local_data_key!(depth: uint); + thread_local!(static DEPTH: Cell = Cell::new(0)); if !do_it { return f(u); } - let old = depth.get().map(|d| *d).unwrap_or(0); - depth.replace(Some(old + 1)); + let old = DEPTH.with(|slot| { + let r = slot.get(); + slot.set(r + 1); + r + }); let mut u = Some(u); let mut rv = None; @@ -41,7 +44,7 @@ pub fn time(do_it: bool, what: &str, u: U, f: |U| -> T) -> T { println!("{}time: {}.{:03} \t{}", " ".repeat(old), dur.num_seconds(), dur.num_milliseconds() % 1000, what); - depth.replace(Some(old)); + DEPTH.with(|slot| slot.set(old)); rv } diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 85085f46731..bdf2eca21d6 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -100,17 +100,20 @@ use syntax::visit::Visitor; use syntax::visit; use syntax::{ast, ast_util, ast_map}; -local_data_key!(task_local_insn_key: RefCell>) +thread_local!(static TASK_LOCAL_INSN_KEY: RefCell>> = { + RefCell::new(None) +}) pub fn with_insn_ctxt(blk: |&[&'static str]|) { - match task_local_insn_key.get() { - Some(ctx) => blk(ctx.borrow().as_slice()), - None => () - } + TASK_LOCAL_INSN_KEY.with(|slot| { + slot.borrow().as_ref().map(|s| blk(s.as_slice())); + }) } pub fn init_insn_ctxt() { - task_local_insn_key.replace(Some(RefCell::new(Vec::new()))); + TASK_LOCAL_INSN_KEY.with(|slot| { + *slot.borrow_mut() = Some(Vec::new()); + }); } pub struct _InsnCtxt { @@ -120,19 +123,23 @@ pub struct _InsnCtxt { #[unsafe_destructor] impl Drop for _InsnCtxt { fn drop(&mut self) { - match task_local_insn_key.get() { - Some(ctx) => { ctx.borrow_mut().pop(); } - None => {} - } + TASK_LOCAL_INSN_KEY.with(|slot| { + match slot.borrow_mut().as_mut() { + Some(ctx) => { ctx.pop(); } + None => {} + } + }) } } pub fn push_ctxt(s: &'static str) -> _InsnCtxt { debug!("new InsnCtxt: {}", s); - match task_local_insn_key.get() { - Some(ctx) => ctx.borrow_mut().push(s), - None => {} - } + TASK_LOCAL_INSN_KEY.with(|slot| { + match slot.borrow_mut().as_mut() { + Some(ctx) => ctx.push(s), + None => {} + } + }); _InsnCtxt { _cannot_construct_outside_of_this_module: () } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index a7f33151547..2b521d1da06 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -26,7 +26,7 @@ use stability_summary::ModuleSummary; use html::item_type; use html::item_type::ItemType; use html::render; -use html::render::{cache_key, current_location_key}; +use html::render::{cache, CURRENT_LOCATION_KEY}; /// Helper to render an optional visibility with a space after it (if the /// visibility is preset) @@ -236,9 +236,9 @@ fn path(w: &mut fmt::Formatter, path: &clean::Path, print_all: bool, generics.push_str(">"); } - let loc = current_location_key.get().unwrap(); - let cache = cache_key.get().unwrap(); - let abs_root = root(&**cache, loc.as_slice()); + let loc = CURRENT_LOCATION_KEY.with(|l| l.borrow().clone()); + let cache = cache(); + let abs_root = root(&*cache, loc.as_slice()); let rel_root = match path.segments[0].name.as_slice() { "self" => Some("./".to_string()), _ => None, @@ -271,7 +271,7 @@ fn path(w: &mut fmt::Formatter, path: &clean::Path, print_all: bool, } } - match info(&**cache) { + match info(&*cache) { // This is a documented path, link to it! Some((ref fqp, shortty)) if abs_root.is_some() => { let mut url = String::from_str(abs_root.unwrap().as_slice()); @@ -308,12 +308,12 @@ fn path(w: &mut fmt::Formatter, path: &clean::Path, print_all: bool, fn primitive_link(f: &mut fmt::Formatter, prim: clean::PrimitiveType, name: &str) -> fmt::Result { - let m = cache_key.get().unwrap(); + let m = cache(); let mut needs_termination = false; match m.primitive_locations.get(&prim) { Some(&ast::LOCAL_CRATE) => { - let loc = current_location_key.get().unwrap(); - let len = if loc.len() == 0 {0} else {loc.len() - 1}; + let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len()); + let len = if len == 0 {0} else {len - 1}; try!(write!(f, "", "../".repeat(len), prim.to_url_str())); @@ -327,8 +327,8 @@ fn primitive_link(f: &mut fmt::Formatter, let loc = match m.extern_locations[cnum] { render::Remote(ref s) => Some(s.to_string()), render::Local => { - let loc = current_location_key.get().unwrap(); - Some("../".repeat(loc.len())) + let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len()); + Some("../".repeat(len)) } render::Unknown => None, }; @@ -371,12 +371,10 @@ impl fmt::Show for clean::Type { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { clean::TyParamBinder(id) => { - let m = cache_key.get().unwrap(); - f.write(m.typarams[ast_util::local_def(id)].as_bytes()) + f.write(cache().typarams[ast_util::local_def(id)].as_bytes()) } clean::Generic(did) => { - let m = cache_key.get().unwrap(); - f.write(m.typarams[did].as_bytes()) + f.write(cache().typarams[did].as_bytes()) } clean::ResolvedPath{ did, ref typarams, ref path } => { try!(resolved_path(f, did, path, false)); diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 07b58e1b66c..11dc8f4f660 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -147,10 +147,14 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> { } } -local_data_key!(used_header_map: RefCell>) -local_data_key!(test_idx: Cell) -// None == render an example, but there's no crate name -local_data_key!(pub playground_krate: Option) +thread_local!(static USED_HEADER_MAP: RefCell> = { + RefCell::new(HashMap::new()) +}) +thread_local!(static TEST_IDX: Cell = Cell::new(0)) + +thread_local!(pub static PLAYGROUND_KRATE: RefCell>> = { + RefCell::new(None) +}) pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { extern fn block(ob: *mut hoedown_buffer, orig_text: *const hoedown_buffer, @@ -183,12 +187,15 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { stripped_filtered_line(*l).is_none() }); let text = lines.collect::>().connect("\n"); - if !rendered { + if rendered { return } + PLAYGROUND_KRATE.with(|krate| { let mut s = String::new(); - let id = playground_krate.get().map(|krate| { - let idx = test_idx.get().unwrap(); - let i = idx.get(); - idx.set(i + 1); + let id = krate.borrow().as_ref().map(|krate| { + let idx = TEST_IDX.with(|slot| { + let i = slot.get(); + slot.set(i + 1); + i + }); let test = origtext.lines().map(|l| { stripped_filtered_line(l).unwrap_or(l) @@ -197,15 +204,15 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { let test = test::maketest(test.as_slice(), krate, false, false); s.push_str(format!("{}", - i, Escape(test.as_slice())).as_slice()); - format!("rust-example-rendered-{}", i) + idx, Escape(test.as_slice())).as_slice()); + format!("rust-example-rendered-{}", idx) }); let id = id.as_ref().map(|a| a.as_slice()); s.push_str(highlight::highlight(text.as_slice(), None, id) .as_slice()); let output = s.to_c_str(); hoedown_buffer_puts(ob, output.as_ptr()); - } + }) } } @@ -229,18 +236,20 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { // This is a terrible hack working around how hoedown gives us rendered // html for text rather than the raw text. - let id = id.replace("", "").replace("", "").to_string(); let opaque = opaque as *mut hoedown_html_renderer_state; let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) }; // Make sure our hyphenated ID is unique for this page - let map = used_header_map.get().unwrap(); - let id = match map.borrow_mut().get_mut(&id) { - None => id, - Some(a) => { *a += 1; format!("{}-{}", id, *a - 1) } - }; - map.borrow_mut().insert(id.clone(), 1); + let id = USED_HEADER_MAP.with(|map| { + let id = id.replace("", "").replace("", "").to_string(); + let id = match map.borrow_mut().get_mut(&id) { + None => id, + Some(a) => { *a += 1; format!("{}-{}", id, *a - 1) } + }; + map.borrow_mut().insert(id.clone(), 1); + id + }); let sec = match opaque.toc_builder { Some(ref mut builder) => { @@ -262,9 +271,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { text.with_c_str(|p| unsafe { hoedown_buffer_puts(ob, p) }); } - if used_header_map.get().is_none() { - reset_headers(); - } + reset_headers(); unsafe { let ob = hoedown_buffer_new(DEF_OUNIT); @@ -418,8 +425,8 @@ impl LangString { /// used at the beginning of rendering an entire HTML page to reset from the /// previous state (if any). pub fn reset_headers() { - used_header_map.replace(Some(RefCell::new(HashMap::new()))); - test_idx.replace(Some(Cell::new(0))); + USED_HEADER_MAP.with(|s| s.borrow_mut().clear()); + TEST_IDX.with(|s| s.set(0)); } impl<'a> fmt::Show for Markdown<'a> { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 9e3c336a7a0..466af36898e 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -34,8 +34,10 @@ //! both occur before the crate is rendered. pub use self::ExternalLocation::*; -use std::collections::{HashMap, HashSet}; +use std::cell::RefCell; use std::collections::hash_map::{Occupied, Vacant}; +use std::collections::{HashMap, HashSet}; +use std::default::Default; use std::fmt; use std::io::fs::PathExtensions; use std::io::{fs, File, BufferedWriter, BufferedReader}; @@ -141,6 +143,7 @@ pub struct Impl { /// to be a fairly large and expensive structure to clone. Instead this adheres /// to `Send` so it may be stored in a `Arc` instance and shared among the various /// rendering tasks. +#[deriving(Default)] pub struct Cache { /// Mapping of typaram ids to the name of the type parameter. This is used /// when pretty-printing a type (so pretty printing doesn't have to @@ -235,8 +238,9 @@ struct IndexItem { // TLS keys used to carry information around during rendering. -local_data_key!(pub cache_key: Arc) -local_data_key!(pub current_location_key: Vec ) +thread_local!(static CACHE_KEY: RefCell> = Default::default()) +thread_local!(pub static CURRENT_LOCATION_KEY: RefCell> = + RefCell::new(Vec::new())) /// Generates the documentation for `crate` into the directory `dst` pub fn run(mut krate: clean::Crate, @@ -280,10 +284,12 @@ pub fn run(mut krate: clean::Crate, clean::NameValue(ref x, ref s) if "html_playground_url" == x.as_slice() => { cx.layout.playground_url = s.to_string(); - let name = krate.name.clone(); - if markdown::playground_krate.get().is_none() { - markdown::playground_krate.replace(Some(Some(name))); - } + markdown::PLAYGROUND_KRATE.with(|slot| { + if slot.borrow().is_none() { + let name = krate.name.clone(); + *slot.borrow_mut() = Some(Some(name)); + } + }); } clean::Word(ref x) if "html_no_source" == x.as_slice() => { @@ -297,7 +303,8 @@ pub fn run(mut krate: clean::Crate, } // Crawl the crate to build various caches used for the output - let analysis = ::analysiskey.get(); + let analysis = ::ANALYSISKEY.with(|a| a.clone()); + let analysis = analysis.borrow(); let public_items = analysis.as_ref().map(|a| a.public_items.clone()); let public_items = public_items.unwrap_or(NodeSet::new()); let paths: HashMap, ItemType)> = @@ -370,8 +377,8 @@ pub fn run(mut krate: clean::Crate, // Freeze the cache now that the index has been built. Put an Arc into TLS // for future parallelization opportunities let cache = Arc::new(cache); - cache_key.replace(Some(cache.clone())); - current_location_key.replace(Some(Vec::new())); + CACHE_KEY.with(|v| *v.borrow_mut() = cache.clone()); + CURRENT_LOCATION_KEY.with(|s| s.borrow_mut().clear()); try!(write_shared(&cx, &krate, &*cache, index)); let krate = try!(render_sources(&mut cx, krate)); @@ -1134,7 +1141,9 @@ impl Context { info!("Rendering an item to {}", w.path().display()); // A little unfortunate that this is done like this, but it sure // does make formatting *a lot* nicer. - current_location_key.replace(Some(cx.current.clone())); + CURRENT_LOCATION_KEY.with(|slot| { + *slot.borrow_mut() = cx.current.clone(); + }); let mut title = cx.current.connect("::"); if pushname { @@ -1177,7 +1186,7 @@ impl Context { &Item{ cx: cx, item: it })); } else { let mut url = "../".repeat(cx.current.len()); - match cache_key.get().unwrap().paths.get(&it.def_id) { + match cache().paths.get(&it.def_id) { Some(&(ref names, _)) => { for name in names[..names.len() - 1].iter() { url.push_str(name.as_slice()); @@ -1324,7 +1333,7 @@ impl<'a> Item<'a> { // If we don't know where the external documentation for this crate is // located, then we return `None`. } else { - let cache = cache_key.get().unwrap(); + let cache = cache(); let path = &cache.external_paths[self.item.def_id]; let root = match cache.extern_locations[self.item.def_id.krate] { Remote(ref s) => s.to_string(), @@ -1751,7 +1760,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, try!(write!(w, "")); } - let cache = cache_key.get().unwrap(); + let cache = cache(); try!(write!(w, "

Implementors