Skip to content

Commit 8c25b7f

Browse files
committed
auto merge of #8740 : brson/rust/rt-opt, r=thestinger
See #8599
2 parents e311a1e + bbe347c commit 8c25b7f

File tree

16 files changed

+240
-217
lines changed

16 files changed

+240
-217
lines changed

Makefile.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ ifdef CFG_DISABLE_OPTIMIZE
9696
$(info cfg: disabling rustc optimization (CFG_DISABLE_OPTIMIZE))
9797
CFG_RUSTC_FLAGS +=
9898
else
99-
CFG_RUSTC_FLAGS += -O
99+
# The rtopt cfg turns off runtime sanity checks
100+
CFG_RUSTC_FLAGS += -O --cfg rtopt
100101
endif
101102

102103
ifdef CFG_ENABLE_DEBUG

src/libstd/macros.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ macro_rules! rtdebug (
2727

2828
macro_rules! rtassert (
2929
( $arg:expr ) => ( {
30-
if !$arg {
31-
rtabort!("assertion failed: %s", stringify!($arg));
30+
if ::rt::util::ENFORCE_SANITY {
31+
if !$arg {
32+
rtabort!("assertion failed: %s", stringify!($arg));
33+
}
3234
}
3335
} )
3436
)

src/libstd/rt/comm.rs

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ impl<T> ChanOne<T> {
125125
unsafe {
126126

127127
// Install the payload
128-
assert!((*packet).payload.is_none());
128+
rtassert!((*packet).payload.is_none());
129129
(*packet).payload = Some(val);
130130

131131
// Atomically swap out the old state to figure out what
@@ -144,16 +144,8 @@ impl<T> ChanOne<T> {
144144
match oldstate {
145145
STATE_BOTH => {
146146
// Port is not waiting yet. Nothing to do
147-
do Local::borrow::<Scheduler, ()> |sched| {
148-
rtdebug!("non-rendezvous send");
149-
sched.metrics.non_rendezvous_sends += 1;
150-
}
151147
}
152148
STATE_ONE => {
153-
do Local::borrow::<Scheduler, ()> |sched| {
154-
rtdebug!("rendezvous send");
155-
sched.metrics.rendezvous_sends += 1;
156-
}
157149
// Port has closed. Need to clean up.
158150
let _packet: ~Packet<T> = cast::transmute(this.void_packet);
159151
recvr_active = false;
@@ -251,7 +243,6 @@ impl<T> SelectInner for PortOne<T> {
251243
STATE_BOTH => {
252244
// Data has not been sent. Now we're blocked.
253245
rtdebug!("non-rendezvous recv");
254-
sched.metrics.non_rendezvous_recvs += 1;
255246
false
256247
}
257248
STATE_ONE => {
@@ -267,7 +258,6 @@ impl<T> SelectInner for PortOne<T> {
267258
(*self.packet()).state.store(STATE_ONE, Relaxed);
268259

269260
rtdebug!("rendezvous recv");
270-
sched.metrics.rendezvous_recvs += 1;
271261

272262
// Channel is closed. Switch back and check the data.
273263
// NB: We have to drop back into the scheduler event loop here
@@ -307,7 +297,7 @@ impl<T> SelectInner for PortOne<T> {
307297
STATE_ONE => true, // Lost the race. Data available.
308298
same_ptr => {
309299
// We successfully unblocked our task pointer.
310-
assert!(task_as_state == same_ptr);
300+
rtassert!(task_as_state == same_ptr);
311301
let handle = BlockedTask::cast_from_uint(task_as_state);
312302
// Because we are already awake, the handle we
313303
// gave to this port shall already be empty.
@@ -341,7 +331,8 @@ impl<T> SelectPortInner<T> for PortOne<T> {
341331
unsafe {
342332
// See corresponding store() above in block_on for rationale.
343333
// FIXME(#8130) This can happen only in test builds.
344-
assert!((*packet).state.load(Relaxed) == STATE_ONE);
334+
// This load is not required for correctness and may be compiled out.
335+
rtassert!((*packet).state.load(Relaxed) == STATE_ONE);
345336

346337
let payload = (*packet).payload.take();
347338

@@ -387,7 +378,7 @@ impl<T> Drop for ChanOne<T> {
387378
},
388379
task_as_state => {
389380
// The port is blocked waiting for a message we will never send. Wake it.
390-
assert!((*this.packet()).payload.is_none());
381+
rtassert!((*this.packet()).payload.is_none());
391382
let recvr = BlockedTask::cast_from_uint(task_as_state);
392383
do recvr.wake().map_move |woken_task| {
393384
Scheduler::run_task(woken_task);

src/libstd/rt/local.rs

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,15 @@ pub trait Local {
2121
fn take() -> ~Self;
2222
fn exists() -> bool;
2323
fn borrow<T>(f: &fn(&mut Self) -> T) -> T;
24+
unsafe fn unsafe_take() -> ~Self;
2425
unsafe fn unsafe_borrow() -> *mut Self;
2526
unsafe fn try_unsafe_borrow() -> Option<*mut Self>;
2627
}
2728

2829
impl Local for Task {
30+
#[inline]
2931
fn put(value: ~Task) { unsafe { local_ptr::put(value) } }
32+
#[inline]
3033
fn take() -> ~Task { unsafe { local_ptr::take() } }
3134
fn exists() -> bool { local_ptr::exists() }
3235
fn borrow<T>(f: &fn(&mut Task) -> T) -> T {
@@ -43,7 +46,11 @@ impl Local for Task {
4346
None => { rtabort!("function failed in local_borrow") }
4447
}
4548
}
49+
#[inline]
50+
unsafe fn unsafe_take() -> ~Task { local_ptr::unsafe_take() }
51+
#[inline]
4652
unsafe fn unsafe_borrow() -> *mut Task { local_ptr::unsafe_borrow() }
53+
#[inline]
4754
unsafe fn try_unsafe_borrow() -> Option<*mut Task> {
4855
local_ptr::try_unsafe_borrow()
4956
}
@@ -57,12 +64,12 @@ impl Local for Scheduler {
5764
task.sched = Some(value.take());
5865
};
5966
}
67+
#[inline]
6068
fn take() -> ~Scheduler {
61-
do Local::borrow::<Task,~Scheduler> |task| {
62-
let sched = task.sched.take_unwrap();
63-
let task = task;
64-
task.sched = None;
65-
sched
69+
unsafe {
70+
// XXX: Unsafe for speed
71+
let task = Local::unsafe_borrow::<Task>();
72+
(*task).sched.take_unwrap()
6673
}
6774
}
6875
fn exists() -> bool {
@@ -85,6 +92,7 @@ impl Local for Scheduler {
8592
}
8693
}
8794
}
95+
unsafe fn unsafe_take() -> ~Scheduler { rtabort!("unimpl") }
8896
unsafe fn unsafe_borrow() -> *mut Scheduler {
8997
match (*Local::unsafe_borrow::<Task>()).sched {
9098
Some(~ref mut sched) => {
@@ -97,10 +105,17 @@ impl Local for Scheduler {
97105
}
98106
}
99107
unsafe fn try_unsafe_borrow() -> Option<*mut Scheduler> {
100-
if Local::exists::<Scheduler>() {
101-
Some(Local::unsafe_borrow())
102-
} else {
103-
None
108+
match Local::try_unsafe_borrow::<Task>() {
109+
Some(task) => {
110+
match (*task).sched {
111+
Some(~ref mut sched) => {
112+
let s: *mut Scheduler = &mut *sched;
113+
Some(s)
114+
}
115+
None => None
116+
}
117+
}
118+
None => None
104119
}
105120
}
106121
}
@@ -111,6 +126,7 @@ impl Local for IoFactoryObject {
111126
fn take() -> ~IoFactoryObject { rtabort!("unimpl") }
112127
fn exists() -> bool { rtabort!("unimpl") }
113128
fn borrow<T>(_f: &fn(&mut IoFactoryObject) -> T) -> T { rtabort!("unimpl") }
129+
unsafe fn unsafe_take() -> ~IoFactoryObject { rtabort!("unimpl") }
114130
unsafe fn unsafe_borrow() -> *mut IoFactoryObject {
115131
let sched = Local::unsafe_borrow::<Scheduler>();
116132
let io: *mut IoFactoryObject = (*sched).event_loop.io().unwrap();

src/libstd/rt/local_ptr.rs

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,16 @@ use option::{Option, Some, None};
2323
use unstable::finally::Finally;
2424
use tls = rt::thread_local_storage;
2525

26+
static mut RT_TLS_KEY: tls::Key = -1;
27+
2628
/// Initialize the TLS key. Other ops will fail if this isn't executed first.
2729
#[fixed_stack_segment]
2830
#[inline(never)]
2931
pub fn init_tls_key() {
3032
unsafe {
31-
rust_initialize_rt_tls_key();
33+
rust_initialize_rt_tls_key(&mut RT_TLS_KEY);
3234
extern {
33-
fn rust_initialize_rt_tls_key();
35+
fn rust_initialize_rt_tls_key(key: *mut tls::Key);
3436
}
3537
}
3638
}
@@ -40,6 +42,7 @@ pub fn init_tls_key() {
4042
/// # Safety note
4143
///
4244
/// Does not validate the pointer type.
45+
#[inline]
4346
pub unsafe fn put<T>(sched: ~T) {
4447
let key = tls_key();
4548
let void_ptr: *mut c_void = cast::transmute(sched);
@@ -51,6 +54,7 @@ pub unsafe fn put<T>(sched: ~T) {
5154
/// # Safety note
5255
///
5356
/// Does not validate the pointer type.
57+
#[inline]
5458
pub unsafe fn take<T>() -> ~T {
5559
let key = tls_key();
5660
let void_ptr: *mut c_void = tls::get(key);
@@ -62,6 +66,23 @@ pub unsafe fn take<T>() -> ~T {
6266
return ptr;
6367
}
6468

69+
/// Take ownership of a pointer from thread-local storage.
70+
///
71+
/// # Safety note
72+
///
73+
/// Does not validate the pointer type.
74+
/// Leaves the old pointer in TLS for speed.
75+
#[inline]
76+
pub unsafe fn unsafe_take<T>() -> ~T {
77+
let key = tls_key();
78+
let void_ptr: *mut c_void = tls::get(key);
79+
if void_ptr.is_null() {
80+
rtabort!("thread-local pointer is null. bogus!");
81+
}
82+
let ptr: ~T = cast::transmute(void_ptr);
83+
return ptr;
84+
}
85+
6586
/// Check whether there is a thread-local pointer installed.
6687
pub fn exists() -> bool {
6788
unsafe {
@@ -99,10 +120,15 @@ pub unsafe fn borrow<T>(f: &fn(&mut T)) {
99120
/// Because this leaves the value in thread-local storage it is possible
100121
/// For the Scheduler pointer to be aliased
101122
pub unsafe fn unsafe_borrow<T>() -> *mut T {
102-
match try_unsafe_borrow() {
103-
Some(p) => p,
104-
None => rtabort!("thread-local pointer is null. bogus!")
123+
let key = tls_key();
124+
let mut void_ptr: *mut c_void = tls::get(key);
125+
if void_ptr.is_null() {
126+
rtabort!("thread-local pointer is null. bogus!");
105127
}
128+
let ptr: *mut *mut c_void = &mut void_ptr;
129+
let ptr: *mut ~T = ptr as *mut ~T;
130+
let ptr: *mut T = &mut **ptr;
131+
return ptr;
106132
}
107133

108134
pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
@@ -119,22 +145,18 @@ pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
119145
}
120146
}
121147

148+
#[inline]
122149
fn tls_key() -> tls::Key {
123150
match maybe_tls_key() {
124151
Some(key) => key,
125152
None => rtabort!("runtime tls key not initialized")
126153
}
127154
}
128155

129-
#[fixed_stack_segment]
130-
#[inline(never)]
131-
fn maybe_tls_key() -> Option<tls::Key> {
156+
#[inline]
157+
#[cfg(not(test))]
158+
pub fn maybe_tls_key() -> Option<tls::Key> {
132159
unsafe {
133-
let key: *mut c_void = rust_get_rt_tls_key();
134-
let key: &mut tls::Key = cast::transmute(key);
135-
let key = *key;
136-
// Check that the key has been initialized.
137-
138160
// NB: This is a little racy because, while the key is
139161
// initalized under a mutex and it's assumed to be initalized
140162
// in the Scheduler ctor by any thread that needs to use it,
@@ -145,14 +167,19 @@ fn maybe_tls_key() -> Option<tls::Key> {
145167
// another thread. I think this is fine since the only action
146168
// they could take if it was initialized would be to check the
147169
// thread-local value and see that it's not set.
148-
if key != -1 {
149-
return Some(key);
170+
if RT_TLS_KEY != -1 {
171+
return Some(RT_TLS_KEY);
150172
} else {
151173
return None;
152174
}
153175
}
176+
}
154177

155-
extern {
156-
fn rust_get_rt_tls_key() -> *mut c_void;
157-
}
178+
// XXX: The boundary between the running runtime and the testing runtime
179+
// seems to be fuzzy at the moment, and trying to use two different keys
180+
// results in disaster. This should not be necessary.
181+
#[inline]
182+
#[cfg(test)]
183+
pub fn maybe_tls_key() -> Option<tls::Key> {
184+
unsafe { ::cast::transmute(::realstd::rt::local_ptr::maybe_tls_key()) }
158185
}

src/libstd/rt/message_queue.rs

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,66 @@ use kinds::Send;
1616
use vec::OwnedVector;
1717
use cell::Cell;
1818
use option::*;
19-
use unstable::sync::Exclusive;
19+
use unstable::sync::{UnsafeAtomicRcBox, LittleLock};
2020
use clone::Clone;
2121

2222
pub struct MessageQueue<T> {
23-
// XXX: Another mystery bug fixed by boxing this lock
24-
priv queue: ~Exclusive<~[T]>
23+
priv state: UnsafeAtomicRcBox<State<T>>
24+
}
25+
26+
struct State<T> {
27+
count: uint,
28+
queue: ~[T],
29+
lock: LittleLock
2530
}
2631

2732
impl<T: Send> MessageQueue<T> {
2833
pub fn new() -> MessageQueue<T> {
2934
MessageQueue {
30-
queue: ~Exclusive::new(~[])
35+
state: UnsafeAtomicRcBox::new(State {
36+
count: 0,
37+
queue: ~[],
38+
lock: LittleLock::new()
39+
})
3140
}
3241
}
3342

3443
pub fn push(&mut self, value: T) {
3544
unsafe {
3645
let value = Cell::new(value);
37-
self.queue.with(|q| q.push(value.take()) );
46+
let state = self.state.get();
47+
do (*state).lock.lock {
48+
(*state).count += 1;
49+
(*state).queue.push(value.take());
50+
}
3851
}
3952
}
4053

4154
pub fn pop(&mut self) -> Option<T> {
4255
unsafe {
43-
do self.queue.with |q| {
44-
if !q.is_empty() {
45-
Some(q.shift())
56+
let state = self.state.get();
57+
do (*state).lock.lock {
58+
if !(*state).queue.is_empty() {
59+
(*state).count += 1;
60+
Some((*state).queue.shift())
61+
} else {
62+
None
63+
}
64+
}
65+
}
66+
}
67+
68+
/// A pop that may sometimes miss enqueued elements, but is much faster
69+
/// to give up without doing any synchronization
70+
pub fn casual_pop(&mut self) -> Option<T> {
71+
unsafe {
72+
let state = self.state.get();
73+
// NB: Unsynchronized check
74+
if (*state).count == 0 { return None; }
75+
do (*state).lock.lock {
76+
if !(*state).queue.is_empty() {
77+
(*state).count += 1;
78+
Some((*state).queue.shift())
4679
} else {
4780
None
4881
}
@@ -51,10 +84,10 @@ impl<T: Send> MessageQueue<T> {
5184
}
5285
}
5386

54-
impl<T> Clone for MessageQueue<T> {
87+
impl<T: Send> Clone for MessageQueue<T> {
5588
fn clone(&self) -> MessageQueue<T> {
5689
MessageQueue {
57-
queue: self.queue.clone()
90+
state: self.state.clone()
5891
}
5992
}
6093
}

0 commit comments

Comments
 (0)