Skip to content

Commit f08f3a7

Browse files
committed
libstd: Remove Cells that were used because of finally by converting
their `finally` blocks to RAII.
1 parent ec5603b commit f08f3a7

File tree

2 files changed

+63
-41
lines changed

2 files changed

+63
-41
lines changed

src/libstd/select.rs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,16 @@
1010

1111
#[allow(missing_doc)];
1212

13-
use cell::Cell;
1413
use comm;
1514
use container::Container;
1615
use iter::{Iterator, DoubleEndedIterator};
16+
use kinds::Send;
17+
use ops::Drop;
1718
use option::*;
18-
// use either::{Either, Left, Right};
19-
// use rt::kill::BlockedTask;
2019
use rt::local::Local;
2120
use rt::rtio::EventLoop;
2221
use rt::sched::Scheduler;
2322
use rt::shouldnt_be_public::{SelectInner, SelectPortInner};
24-
use unstable::finally::Finally;
2523
use vec::{OwnedVector, MutableVector};
2624

2725
/// Trait for message-passing primitives that can be select()ed on.
@@ -32,6 +30,18 @@ pub trait Select : SelectInner { }
3230
// that implement Select on different types to use select().)
3331
pub trait SelectPort<T> : SelectPortInner<T> { }
3432

33+
/// A helper type that throws away a value on a port.
34+
struct PortGuard<T> {
35+
port: Option<comm::PortOne<T>>,
36+
}
37+
38+
#[unsafe_destructor]
39+
impl<T:Send> Drop for PortGuard<T> {
40+
fn drop(&mut self) {
41+
let _ = self.port.take_unwrap().recv();
42+
}
43+
}
44+
3545
/// Receive a message from any one of many ports at once. Returns the index of the
3646
/// port whose data is ready. (If multiple are ready, returns the lowest index.)
3747
pub fn select<A: Select>(ports: &mut [A]) -> uint {
@@ -56,11 +66,13 @@ pub fn select<A: Select>(ports: &mut [A]) -> uint {
5666
// after letting the task get woken up. The and_then closure needs to delay
5767
// the task from resuming until all ports have become blocked_on.
5868
let (p,c) = comm::oneshot();
59-
let p = Cell::new(p);
60-
let c = Cell::new(c);
6169

62-
(|| {
63-
let mut c = Some(c.take());
70+
{
71+
let _guard = PortGuard {
72+
port: Some(p),
73+
};
74+
75+
let mut c = Some(c);
6476
let sched: ~Scheduler = Local::take();
6577
sched.deschedule_running_task_and_then(|sched, task| {
6678
let task_handles = task.make_selectable(ports.len());
@@ -79,12 +91,7 @@ pub fn select<A: Select>(ports: &mut [A]) -> uint {
7991
c.send_deferred(())
8092
}
8193
})
82-
}).finally(|| {
83-
// Unkillable is necessary not because getting killed is dangerous here,
84-
// but to force the recv not to use the same kill-flag that we used for
85-
// selecting. Otherwise a user-sender could spuriously wakeup us here.
86-
p.take().recv();
87-
});
94+
}
8895

8996
// Task resumes. Now unblock ourselves from all the ports we blocked on.
9097
// If the success index wasn't reset, 'take' will just take all of them.

src/libstd/unstable/sync.rs

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
// except according to those terms.
1010

1111
use cast;
12-
use cell::Cell;
1312
use comm;
1413
use ptr;
1514
use option::{Option,Some,None};
@@ -70,6 +69,35 @@ unsafe fn new_inner<T: Send>(data: T, refcount: uint) -> *mut ArcData<T> {
7069
cast::transmute(data)
7170
}
7271

72+
/// A helper object used by `UnsafeArc::unwrap`.
73+
struct ChannelAndDataGuard<T> {
74+
channel: Option<comm::ChanOne<bool>>,
75+
data: Option<~ArcData<T>>,
76+
}
77+
78+
#[unsafe_destructor]
79+
impl<T> Drop for ChannelAndDataGuard<T> {
80+
fn drop(&mut self) {
81+
if task::failing() {
82+
// Killed during wait. Because this might happen while
83+
// someone else still holds a reference, we can't free
84+
// the data now; the "other" last refcount will free it.
85+
unsafe {
86+
let channel = self.channel.take_unwrap();
87+
let data = self.data.take_unwrap();
88+
channel.send(false);
89+
cast::forget(data);
90+
}
91+
}
92+
}
93+
}
94+
95+
impl<T> ChannelAndDataGuard<T> {
96+
fn unwrap(mut self) -> (comm::ChanOne<bool>, ~ArcData<T>) {
97+
(self.channel.take_unwrap(), self.data.take_unwrap())
98+
}
99+
}
100+
73101
impl<T: Send> UnsafeArc<T> {
74102
pub fn new(data: T) -> UnsafeArc<T> {
75103
unsafe { UnsafeArc { data: new_inner(data, 1) } }
@@ -160,32 +188,19 @@ impl<T: Send> UnsafeArc<T> {
160188
data.data.take_unwrap()
161189
} else {
162190
// The *next* person who sees the refcount hit 0 will wake us.
163-
let p1 = Cell::new(p1); // argh
164-
// Unlike the above one, this cell is necessary. It will get
165-
// taken either in the do block or in the finally block.
166-
let c2_and_data = Cell::new((c2,data));
167-
(|| {
168-
p1.take().recv();
169-
// Got here. Back in the 'unkillable' without getting killed.
170-
let (c2, data) = c2_and_data.take();
171-
c2.send(true);
172-
// FIXME(#3224): it should be like this
173-
// let ~ArcData { data: user_data, _ } = data;
174-
// user_data
175-
let mut data = data;
176-
data.data.take_unwrap()
177-
}).finally(|| {
178-
if task::failing() {
179-
// Killed during wait. Because this might happen while
180-
// someone else still holds a reference, we can't free
181-
// the data now; the "other" last refcount will free it.
182-
let (c2, data) = c2_and_data.take();
183-
c2.send(false);
184-
cast::forget(data);
185-
} else {
186-
assert!(c2_and_data.is_empty());
187-
}
188-
})
191+
let c2_and_data = ChannelAndDataGuard {
192+
channel: Some(c2),
193+
data: Some(data),
194+
};
195+
p1.recv();
196+
// Got here. Back in the 'unkillable' without getting killed.
197+
let (c2, data) = c2_and_data.unwrap();
198+
c2.send(true);
199+
// FIXME(#3224): it should be like this
200+
// let ~ArcData { data: user_data, _ } = data;
201+
// user_data
202+
let mut data = data;
203+
data.data.take_unwrap()
189204
}
190205
} else {
191206
// If 'put' returns the server end back to us, we were rejected;

0 commit comments

Comments
 (0)