Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix sending/try_recv on channels from off the runtime #12397

Merged
merged 1 commit into from
Feb 20, 2014
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 49 additions & 10 deletions src/libstd/comm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,17 +385,17 @@ impl<T: Send> Chan<T> {
pub fn try_send(&self, t: T) -> bool {
// In order to prevent starvation of other tasks in situations where
// a task sends repeatedly without ever receiving, we occassionally
// yield instead of doing a send immediately. Only doing this if
// we're doing a rescheduling send, otherwise the caller is
// expecting not to context switch.
// yield instead of doing a send immediately.
//
// Note that we don't unconditionally attempt to yield because the
// TLS overhead can be a bit much.
// Don't unconditionally attempt to yield because the TLS overhead can
// be a bit much, and also use `try_take` instead of `take` because
// there's no reason that this send shouldn't be usable off the
// runtime.
let cnt = self.sends.get() + 1;
self.sends.set(cnt);
if cnt % (RESCHED_FREQ as uint) == 0 {
let task: ~Task = Local::take();
task.maybe_yield();
let task: Option<~Task> = Local::try_take();
task.map(|t| t.maybe_yield());
}

let (new_inner, ret) = match self.inner {
Expand Down Expand Up @@ -521,12 +521,13 @@ impl<T: Send> Port<T> {
pub fn try_recv(&self) -> TryRecvResult<T> {
// If a thread is spinning in try_recv, we should take the opportunity
// to reschedule things occasionally. See notes above in scheduling on
// sends for why this doesn't always hit TLS.
// sends for why this doesn't always hit TLS, and also for why this uses
// `try_take` instead of `take`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E-needstest

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, thanks! I've added one.

let cnt = self.receives.get() + 1;
self.receives.set(cnt);
if cnt % (RESCHED_FREQ as uint) == 0 {
let task: ~Task = Local::take();
task.maybe_yield();
let task: Option<~Task> = Local::try_take();
task.map(|t| t.maybe_yield());
}

loop {
Expand Down Expand Up @@ -1203,4 +1204,42 @@ mod test {
// wait for the child task to exit before we exit
p1.recv();
})

test!(fn sends_off_the_runtime() {
use rt::thread::Thread;

let (p, c) = Chan::new();
let t = Thread::start(proc() {
for _ in range(0, 1000) {
c.send(());
}
});
for _ in range(0, 1000) {
p.recv();
}
t.join();
})

test!(fn try_recvs_off_the_runtime() {
use rt::thread::Thread;

let (p, c) = Chan::new();
let (pdone, cdone) = Chan::new();
let t = Thread::start(proc() {
let mut hits = 0;
while hits < 10 {
match p.try_recv() {
Data(()) => { hits += 1; }
Empty => { Thread::yield_now(); }
Disconnected => return,
}
}
cdone.send(());
});
for _ in range(0, 10) {
c.send(());
}
t.join();
pdone.recv();
})
}