Skip to content

Commit 7326bc8

Browse files
committed
Optimize try_recv to not require the two context switches when data is available.
1 parent 1137fbd commit 7326bc8

File tree

1 file changed

+34
-31
lines changed

1 file changed

+34
-31
lines changed

src/libstd/rt/comm.rs

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rt::kill::BlockedTask;
1818
use kinds::Send;
1919
use rt::sched::Scheduler;
2020
use rt::local::Local;
21-
use unstable::atomics::{AtomicUint, AtomicOption, SeqCst};
21+
use unstable::atomics::{AtomicUint, AtomicOption, Acquire, SeqCst};
2222
use unstable::sync::UnsafeAtomicRcBox;
2323
use util::Void;
2424
use comm::{GenericChan, GenericSmartChan, GenericPort, Peekable};
@@ -164,36 +164,39 @@ impl<T> PortOne<T> {
164164
let mut this = self;
165165
let packet = this.packet();
166166

167-
// XXX: Optimize this to not require the two context switches when data is available
168-
169-
// Switch to the scheduler to put the ~Task into the Packet state.
170-
let sched = Local::take::<Scheduler>();
171-
do sched.deschedule_running_task_and_then |sched, task| {
172-
unsafe {
173-
// Atomically swap the task pointer into the Packet state, issuing
174-
// an acquire barrier to prevent reordering of the subsequent read
175-
// of the payload. Also issues a release barrier to prevent reordering
176-
// of any previous writes to the task structure.
177-
let task_as_state = task.cast_to_uint();
178-
let oldstate = (*packet).state.swap(task_as_state, SeqCst);
179-
match oldstate {
180-
STATE_BOTH => {
181-
// Data has not been sent. Now we're blocked.
182-
rtdebug!("non-rendezvous recv");
183-
sched.metrics.non_rendezvous_recvs += 1;
167+
// Optimistic check. If data was sent already, we don't even need to block.
168+
// No release barrier needed here; we're not handing off our task pointer yet.
169+
if unsafe { (*packet).state.load(Acquire) } != STATE_ONE {
170+
// No data available yet.
171+
// Switch to the scheduler to put the ~Task into the Packet state.
172+
let sched = Local::take::<Scheduler>();
173+
do sched.deschedule_running_task_and_then |sched, task| {
174+
unsafe {
175+
// Atomically swap the task pointer into the Packet state, issuing
176+
// an acquire barrier to prevent reordering of the subsequent read
177+
// of the payload. Also issues a release barrier to prevent
178+
// reordering of any previous writes to the task structure.
179+
let task_as_state = task.cast_to_uint();
180+
let oldstate = (*packet).state.swap(task_as_state, SeqCst);
181+
match oldstate {
182+
STATE_BOTH => {
183+
// Data has not been sent. Now we're blocked.
184+
rtdebug!("non-rendezvous recv");
185+
sched.metrics.non_rendezvous_recvs += 1;
186+
}
187+
STATE_ONE => {
188+
rtdebug!("rendezvous recv");
189+
sched.metrics.rendezvous_recvs += 1;
190+
191+
// Channel is closed. Switch back and check the data.
192+
// NB: We have to drop back into the scheduler event loop here
193+
// instead of switching immediately back or we could end up
194+
// triggering infinite recursion on the scheduler's stack.
195+
let recvr = BlockedTask::cast_from_uint(task_as_state);
196+
sched.enqueue_blocked_task(recvr);
197+
}
198+
_ => util::unreachable()
184199
}
185-
STATE_ONE => {
186-
rtdebug!("rendezvous recv");
187-
sched.metrics.rendezvous_recvs += 1;
188-
189-
// Channel is closed. Switch back and check the data.
190-
// NB: We have to drop back into the scheduler event loop here
191-
// instead of switching immediately back or we could end up
192-
// triggering infinite recursion on the scheduler's stack.
193-
let recvr = BlockedTask::cast_from_uint(task_as_state);
194-
sched.enqueue_blocked_task(recvr);
195-
}
196-
_ => util::unreachable()
197200
}
198201
}
199202
}
@@ -212,7 +215,7 @@ impl<T> PortOne<T> {
212215
// a different scheduler for resuming. That send synchronized memory.
213216

214217
unsafe {
215-
let payload = util::replace(&mut (*packet).payload, None);
218+
let payload = (*packet).payload.take();
216219

217220
// The sender has closed up shop. Drop the packet.
218221
let _packet: ~Packet<T> = cast::transmute(this.void_packet);

0 commit comments

Comments
 (0)