Skip to content

Commit 87e21d6

Browse files
committed
auto merge of #19094 : alexcrichton/rust/rm-std-local-data, r=aturon
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 tls 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]: rust-lang/rfcs#461 [breaking-change]
2 parents caec7b0 + 647d38d commit 87e21d6

38 files changed

+1805
-1164
lines changed

Diff for: src/liblog/lib.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@
171171

172172
extern crate regex;
173173

174-
use regex::Regex;
174+
use std::cell::RefCell;
175175
use std::fmt;
176176
use std::io::LineBufferedWriter;
177177
use std::io;
@@ -181,6 +181,8 @@ use std::rt;
181181
use std::slice;
182182
use std::sync::{Once, ONCE_INIT};
183183

184+
use regex::Regex;
185+
184186
use directive::LOG_LEVEL_NAMES;
185187

186188
pub mod macros;
@@ -213,7 +215,9 @@ pub const WARN: u32 = 2;
213215
/// Error log level
214216
pub const ERROR: u32 = 1;
215217

216-
local_data_key!(local_logger: Box<Logger + Send>)
218+
thread_local!(static LOCAL_LOGGER: RefCell<Option<Box<Logger + Send>>> = {
219+
RefCell::new(None)
220+
})
217221

218222
/// A trait used to represent an interface to a task-local logger. Each task
219223
/// 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) {
283287
// Completely remove the local logger from TLS in case anyone attempts to
284288
// frob the slot while we're doing the logging. This will destroy any logger
285289
// set during logging.
286-
let mut logger = local_logger.replace(None).unwrap_or_else(|| {
290+
let mut logger = LOCAL_LOGGER.with(|s| {
291+
s.borrow_mut().take()
292+
}).unwrap_or_else(|| {
287293
box DefaultLogger { handle: io::stderr() } as Box<Logger + Send>
288294
});
289295
logger.log(&LogRecord {
@@ -293,7 +299,7 @@ pub fn log(level: u32, loc: &'static LogLocation, args: &fmt::Arguments) {
293299
module_path: loc.module_path,
294300
line: loc.line,
295301
});
296-
local_logger.replace(Some(logger));
302+
set_logger(logger);
297303
}
298304

299305
/// 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 } }
305311
/// Replaces the task-local logger with the specified logger, returning the old
306312
/// logger.
307313
pub fn set_logger(logger: Box<Logger + Send>) -> Option<Box<Logger + Send>> {
308-
local_logger.replace(Some(logger))
314+
let mut l = Some(logger);
315+
LOCAL_LOGGER.with(|slot| {
316+
mem::replace(&mut *slot.borrow_mut(), l.take())
317+
})
309318
}
310319

311320
/// A LogRecord is created by the logging macros, and passed as the only

Diff for: src/librustc/util/common.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
#![allow(non_camel_case_types)]
1212

13-
use std::cell::RefCell;
13+
use std::cell::{RefCell, Cell};
1414
use std::collections::HashMap;
1515
use std::fmt::Show;
1616
use std::hash::{Hash, Hasher};
@@ -26,11 +26,14 @@ use syntax::visit::Visitor;
2626
pub struct ErrorReported;
2727

2828
pub fn time<T, U>(do_it: bool, what: &str, u: U, f: |U| -> T) -> T {
29-
local_data_key!(depth: uint);
29+
thread_local!(static DEPTH: Cell<uint> = Cell::new(0));
3030
if !do_it { return f(u); }
3131

32-
let old = depth.get().map(|d| *d).unwrap_or(0);
33-
depth.replace(Some(old + 1));
32+
let old = DEPTH.with(|slot| {
33+
let r = slot.get();
34+
slot.set(r + 1);
35+
r
36+
});
3437

3538
let mut u = Some(u);
3639
let mut rv = None;
@@ -41,7 +44,7 @@ pub fn time<T, U>(do_it: bool, what: &str, u: U, f: |U| -> T) -> T {
4144

4245
println!("{}time: {}.{:03} \t{}", " ".repeat(old),
4346
dur.num_seconds(), dur.num_milliseconds() % 1000, what);
44-
depth.replace(Some(old));
47+
DEPTH.with(|slot| slot.set(old));
4548

4649
rv
4750
}

Diff for: src/librustc_trans/trans/base.rs

+21-14
Original file line numberDiff line numberDiff line change
@@ -100,17 +100,20 @@ use syntax::visit::Visitor;
100100
use syntax::visit;
101101
use syntax::{ast, ast_util, ast_map};
102102

103-
local_data_key!(task_local_insn_key: RefCell<Vec<&'static str>>)
103+
thread_local!(static TASK_LOCAL_INSN_KEY: RefCell<Option<Vec<&'static str>>> = {
104+
RefCell::new(None)
105+
})
104106

105107
pub fn with_insn_ctxt(blk: |&[&'static str]|) {
106-
match task_local_insn_key.get() {
107-
Some(ctx) => blk(ctx.borrow().as_slice()),
108-
None => ()
109-
}
108+
TASK_LOCAL_INSN_KEY.with(|slot| {
109+
slot.borrow().as_ref().map(|s| blk(s.as_slice()));
110+
})
110111
}
111112

112113
pub fn init_insn_ctxt() {
113-
task_local_insn_key.replace(Some(RefCell::new(Vec::new())));
114+
TASK_LOCAL_INSN_KEY.with(|slot| {
115+
*slot.borrow_mut() = Some(Vec::new());
116+
});
114117
}
115118

116119
pub struct _InsnCtxt {
@@ -120,19 +123,23 @@ pub struct _InsnCtxt {
120123
#[unsafe_destructor]
121124
impl Drop for _InsnCtxt {
122125
fn drop(&mut self) {
123-
match task_local_insn_key.get() {
124-
Some(ctx) => { ctx.borrow_mut().pop(); }
125-
None => {}
126-
}
126+
TASK_LOCAL_INSN_KEY.with(|slot| {
127+
match slot.borrow_mut().as_mut() {
128+
Some(ctx) => { ctx.pop(); }
129+
None => {}
130+
}
131+
})
127132
}
128133
}
129134

130135
pub fn push_ctxt(s: &'static str) -> _InsnCtxt {
131136
debug!("new InsnCtxt: {}", s);
132-
match task_local_insn_key.get() {
133-
Some(ctx) => ctx.borrow_mut().push(s),
134-
None => {}
135-
}
137+
TASK_LOCAL_INSN_KEY.with(|slot| {
138+
match slot.borrow_mut().as_mut() {
139+
Some(ctx) => ctx.push(s),
140+
None => {}
141+
}
142+
});
136143
_InsnCtxt { _cannot_construct_outside_of_this_module: () }
137144
}
138145

Diff for: src/librustdoc/html/format.rs

+12-14
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use stability_summary::ModuleSummary;
2626
use html::item_type;
2727
use html::item_type::ItemType;
2828
use html::render;
29-
use html::render::{cache_key, current_location_key};
29+
use html::render::{cache, CURRENT_LOCATION_KEY};
3030

3131
/// Helper to render an optional visibility with a space after it (if the
3232
/// visibility is preset)
@@ -236,9 +236,9 @@ fn path(w: &mut fmt::Formatter, path: &clean::Path, print_all: bool,
236236
generics.push_str("&gt;");
237237
}
238238

239-
let loc = current_location_key.get().unwrap();
240-
let cache = cache_key.get().unwrap();
241-
let abs_root = root(&**cache, loc.as_slice());
239+
let loc = CURRENT_LOCATION_KEY.with(|l| l.borrow().clone());
240+
let cache = cache();
241+
let abs_root = root(&*cache, loc.as_slice());
242242
let rel_root = match path.segments[0].name.as_slice() {
243243
"self" => Some("./".to_string()),
244244
_ => None,
@@ -271,7 +271,7 @@ fn path(w: &mut fmt::Formatter, path: &clean::Path, print_all: bool,
271271
}
272272
}
273273

274-
match info(&**cache) {
274+
match info(&*cache) {
275275
// This is a documented path, link to it!
276276
Some((ref fqp, shortty)) if abs_root.is_some() => {
277277
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,
308308
fn primitive_link(f: &mut fmt::Formatter,
309309
prim: clean::PrimitiveType,
310310
name: &str) -> fmt::Result {
311-
let m = cache_key.get().unwrap();
311+
let m = cache();
312312
let mut needs_termination = false;
313313
match m.primitive_locations.get(&prim) {
314314
Some(&ast::LOCAL_CRATE) => {
315-
let loc = current_location_key.get().unwrap();
316-
let len = if loc.len() == 0 {0} else {loc.len() - 1};
315+
let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
316+
let len = if len == 0 {0} else {len - 1};
317317
try!(write!(f, "<a href='{}primitive.{}.html'>",
318318
"../".repeat(len),
319319
prim.to_url_str()));
@@ -327,8 +327,8 @@ fn primitive_link(f: &mut fmt::Formatter,
327327
let loc = match m.extern_locations[cnum] {
328328
render::Remote(ref s) => Some(s.to_string()),
329329
render::Local => {
330-
let loc = current_location_key.get().unwrap();
331-
Some("../".repeat(loc.len()))
330+
let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
331+
Some("../".repeat(len))
332332
}
333333
render::Unknown => None,
334334
};
@@ -371,12 +371,10 @@ impl fmt::Show for clean::Type {
371371
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
372372
match *self {
373373
clean::TyParamBinder(id) => {
374-
let m = cache_key.get().unwrap();
375-
f.write(m.typarams[ast_util::local_def(id)].as_bytes())
374+
f.write(cache().typarams[ast_util::local_def(id)].as_bytes())
376375
}
377376
clean::Generic(did) => {
378-
let m = cache_key.get().unwrap();
379-
f.write(m.typarams[did].as_bytes())
377+
f.write(cache().typarams[did].as_bytes())
380378
}
381379
clean::ResolvedPath{ did, ref typarams, ref path } => {
382380
try!(resolved_path(f, did, path, false));

Diff for: src/librustdoc/html/markdown.rs

+44-38
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,14 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
147147
}
148148
}
149149

150-
local_data_key!(used_header_map: RefCell<HashMap<String, uint>>)
151-
local_data_key!(test_idx: Cell<uint>)
152-
// None == render an example, but there's no crate name
153-
local_data_key!(pub playground_krate: Option<String>)
150+
thread_local!(static USED_HEADER_MAP: RefCell<HashMap<String, uint>> = {
151+
RefCell::new(HashMap::new())
152+
})
153+
thread_local!(static TEST_IDX: Cell<uint> = Cell::new(0))
154+
155+
thread_local!(pub static PLAYGROUND_KRATE: RefCell<Option<Option<String>>> = {
156+
RefCell::new(None)
157+
})
154158

155159
pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
156160
extern fn block(ob: *mut hoedown_buffer, orig_text: *const hoedown_buffer,
@@ -184,29 +188,31 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
184188
stripped_filtered_line(*l).is_none()
185189
});
186190
let text = lines.collect::<Vec<&str>>().connect("\n");
187-
if !rendered {
188-
let mut s = String::new();
189-
let id = playground_krate.get().map(|krate| {
190-
let idx = test_idx.get().unwrap();
191-
let i = idx.get();
192-
idx.set(i + 1);
193-
194-
let test = origtext.lines().map(|l| {
195-
stripped_filtered_line(l).unwrap_or(l)
196-
}).collect::<Vec<&str>>().connect("\n");
197-
let krate = krate.as_ref().map(|s| s.as_slice());
198-
let test = test::maketest(test.as_slice(), krate, false, false);
199-
s.push_str(format!("<span id='rust-example-raw-{}' \
200-
class='rusttest'>{}</span>",
201-
i, Escape(test.as_slice())).as_slice());
202-
format!("rust-example-rendered-{}", i)
191+
if rendered { return }
192+
let mut s = String::new();
193+
let krate = PLAYGROUND_KRATE.with(|c| c.borrow().clone());
194+
let id = krate.as_ref().map(|krate| {
195+
let i = TEST_IDX.with(|slot| {
196+
let r = slot.get();
197+
slot.set(r + 1);
198+
r
203199
});
204-
let id = id.as_ref().map(|a| a.as_slice());
205-
s.push_str(highlight::highlight(text.as_slice(), None, id)
206-
.as_slice());
207-
let output = s.to_c_str();
208-
hoedown_buffer_puts(ob, output.as_ptr());
209-
}
200+
201+
let test = origtext.lines().map(|l| {
202+
stripped_filtered_line(l).unwrap_or(l)
203+
}).collect::<Vec<&str>>().connect("\n");
204+
let krate = krate.as_ref().map(|s| s.as_slice());
205+
let test = test::maketest(test.as_slice(), krate, false, false);
206+
s.push_str(format!("<span id='rust-example-raw-{}' \
207+
class='rusttest'>{}</span>",
208+
i, Escape(test.as_slice())).as_slice());
209+
format!("rust-example-rendered-{}", i)
210+
});
211+
let id = id.as_ref().map(|i| i.as_slice());
212+
s.push_str(highlight::highlight(text.as_slice(), None, id)
213+
.as_slice());
214+
let output = s.to_c_str();
215+
hoedown_buffer_puts(ob, output.as_ptr());
210216
})
211217
}
212218
}
@@ -235,18 +241,20 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
235241

236242
// This is a terrible hack working around how hoedown gives us rendered
237243
// html for text rather than the raw text.
238-
let id = id.replace("<code>", "").replace("</code>", "").to_string();
239244

240245
let opaque = opaque as *mut hoedown_html_renderer_state;
241246
let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) };
242247

243248
// Make sure our hyphenated ID is unique for this page
244-
let map = used_header_map.get().unwrap();
245-
let id = match map.borrow_mut().get_mut(&id) {
246-
None => id,
247-
Some(a) => { *a += 1; format!("{}-{}", id, *a - 1) }
248-
};
249-
map.borrow_mut().insert(id.clone(), 1);
249+
let id = USED_HEADER_MAP.with(|map| {
250+
let id = id.replace("<code>", "").replace("</code>", "").to_string();
251+
let id = match map.borrow_mut().get_mut(&id) {
252+
None => id,
253+
Some(a) => { *a += 1; format!("{}-{}", id, *a - 1) }
254+
};
255+
map.borrow_mut().insert(id.clone(), 1);
256+
id
257+
});
250258

251259
let sec = match opaque.toc_builder {
252260
Some(ref mut builder) => {
@@ -268,9 +276,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
268276
text.with_c_str(|p| unsafe { hoedown_buffer_puts(ob, p) });
269277
}
270278

271-
if used_header_map.get().is_none() {
272-
reset_headers();
273-
}
279+
reset_headers();
274280

275281
unsafe {
276282
let ob = hoedown_buffer_new(DEF_OUNIT);
@@ -428,8 +434,8 @@ impl LangString {
428434
/// used at the beginning of rendering an entire HTML page to reset from the
429435
/// previous state (if any).
430436
pub fn reset_headers() {
431-
used_header_map.replace(Some(RefCell::new(HashMap::new())));
432-
test_idx.replace(Some(Cell::new(0)));
437+
USED_HEADER_MAP.with(|s| s.borrow_mut().clear());
438+
TEST_IDX.with(|s| s.set(0));
433439
}
434440

435441
impl<'a> fmt::Show for Markdown<'a> {

0 commit comments

Comments
 (0)