#![allow(dead_code)]
#![unstable(feature = "mpsc_select",
reason = "This implementation, while likely sufficient, is unsafe and \
likely to be error prone. At some point in the future this \
module will be removed.",
issue = "27800")]
#![rustc_deprecated(since = "1.32.0",
reason = "channel selection will be removed in a future release")]
use fmt;
use core::cell::{Cell, UnsafeCell};
use core::marker;
use core::ptr;
use core::usize;
use sync::mpsc::{Receiver, RecvError};
use sync::mpsc::blocking::{self, SignalToken};
pub struct Select {
inner: UnsafeCell<SelectInner>,
next_id: Cell<usize>,
}
struct SelectInner {
head: *mut Handle<'static, ()>,
tail: *mut Handle<'static, ()>,
}
impl !marker::Send for Select {}
pub struct Handle<'rx, T:Send+'rx> {
id: usize,
selector: *mut SelectInner,
next: *mut Handle<'static, ()>,
prev: *mut Handle<'static, ()>,
added: bool,
packet: &'rx (dyn Packet+'rx),
rx: &'rx Receiver<T>,
}
struct Packets { cur: *mut Handle<'static, ()> }
#[doc(hidden)]
#[derive(PartialEq, Eq)]
pub enum StartResult {
Installed,
Abort,
}
#[doc(hidden)]
pub trait Packet {
fn can_recv(&self) -> bool;
fn start_selection(&self, token: SignalToken) -> StartResult;
fn abort_selection(&self) -> bool;
}
impl Select {
pub fn new() -> Select {
Select {
inner: UnsafeCell::new(SelectInner {
head: ptr::null_mut(),
tail: ptr::null_mut(),
}),
next_id: Cell::new(1),
}
}
pub fn handle<'a, T: Send>(&'a self, rx: &'a Receiver<T>) -> Handle<'a, T> {
let id = self.next_id.get();
self.next_id.set(id + 1);
Handle {
id,
selector: self.inner.get(),
next: ptr::null_mut(),
prev: ptr::null_mut(),
added: false,
rx,
packet: rx,
}
}
pub fn wait(&self) -> usize {
self.wait2(true)
}
fn wait2(&self, do_preflight_checks: bool) -> usize {
unsafe {
if do_preflight_checks {
for handle in self.iter() {
if (*handle).packet.can_recv() {
return (*handle).id();
}
}
}
let (wait_token, signal_token) = blocking::tokens();
for (i, handle) in self.iter().enumerate() {
match (*handle).packet.start_selection(signal_token.clone()) {
StartResult::Installed => {}
StartResult::Abort => {
for handle in self.iter().take(i) {
(*handle).packet.abort_selection();
}
return (*handle).id;
}
}
}
wait_token.wait();
let mut ready_id = usize::MAX;
for handle in self.iter() {
if (*handle).packet.abort_selection() {
ready_id = (*handle).id;
}
}
assert!(ready_id != usize::MAX);
return ready_id;
}
}
fn iter(&self) -> Packets { Packets { cur: unsafe { &*self.inner.get() }.head } }
}
impl<'rx, T: Send> Handle<'rx, T> {
#[inline]
pub fn id(&self) -> usize { self.id }
pub fn recv(&mut self) -> Result<T, RecvError> { self.rx.recv() }
pub unsafe fn add(&mut self) {
if self.added { return }
let selector = &mut *self.selector;
let me = self as *mut Handle<'rx, T> as *mut Handle<'static, ()>;
if selector.head.is_null() {
selector.head = me;
selector.tail = me;
} else {
(*me).prev = selector.tail;
assert!((*me).next.is_null());
(*selector.tail).next = me;
selector.tail = me;
}
self.added = true;
}
pub unsafe fn remove(&mut self) {
if !self.added { return }
let selector = &mut *self.selector;
let me = self as *mut Handle<'rx, T> as *mut Handle<'static, ()>;
if self.prev.is_null() {
assert_eq!(selector.head, me);
selector.head = self.next;
} else {
(*self.prev).next = self.next;
}
if self.next.is_null() {
assert_eq!(selector.tail, me);
selector.tail = self.prev;
} else {
(*self.next).prev = self.prev;
}
self.next = ptr::null_mut();
self.prev = ptr::null_mut();
self.added = false;
}
}
impl Drop for Select {
fn drop(&mut self) {
unsafe {
assert!((&*self.inner.get()).head.is_null());
assert!((&*self.inner.get()).tail.is_null());
}
}
}
impl<'rx, T: Send> Drop for Handle<'rx, T> {
fn drop(&mut self) {
unsafe { self.remove() }
}
}
impl Iterator for Packets {
type Item = *mut Handle<'static, ()>;
fn next(&mut self) -> Option<*mut Handle<'static, ()>> {
if self.cur.is_null() {
None
} else {
let ret = Some(self.cur);
unsafe { self.cur = (*self.cur).next; }
ret
}
}
}
impl fmt::Debug for Select {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Select").finish()
}
}
impl<'rx, T:Send+'rx> fmt::Debug for Handle<'rx, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Handle").finish()
}
}
#[allow(unused_imports)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use thread;
use sync::mpsc::*;
macro_rules! select {
(
$($name:pat = $rx:ident.$meth:ident() => $code:expr),+
) => ({
let sel = Select::new();
$( let mut $rx = sel.handle(&$rx); )+
unsafe {
$( $rx.add(); )+
}
let ret = sel.wait();
$( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+
{ unreachable!() }
})
}
#[test]
fn smoke() {
let (tx1, rx1) = channel::<i32>();
let (tx2, rx2) = channel::<i32>();
tx1.send(1).unwrap();
select! {
foo = rx1.recv() => { assert_eq!(foo.unwrap(), 1); },
_bar = rx2.recv() => { panic!() }
}
tx2.send(2).unwrap();
select! {
_foo = rx1.recv() => { panic!() },
bar = rx2.recv() => { assert_eq!(bar.unwrap(), 2) }
}
drop(tx1);
select! {
foo = rx1.recv() => { assert!(foo.is_err()); },
_bar = rx2.recv() => { panic!() }
}
drop(tx2);
select! {
bar = rx2.recv() => { assert!(bar.is_err()); }
}
}
#[test]
fn smoke2() {
let (_tx1, rx1) = channel::<i32>();
let (_tx2, rx2) = channel::<i32>();
let (_tx3, rx3) = channel::<i32>();
let (_tx4, rx4) = channel::<i32>();
let (tx5, rx5) = channel::<i32>();
tx5.send(4).unwrap();
select! {
_foo = rx1.recv() => { panic!("1") },
_foo = rx2.recv() => { panic!("2") },
_foo = rx3.recv() => { panic!("3") },
_foo = rx4.recv() => { panic!("4") },
foo = rx5.recv() => { assert_eq!(foo.unwrap(), 4); }
}
}
#[test]
fn closed() {
let (_tx1, rx1) = channel::<i32>();
let (tx2, rx2) = channel::<i32>();
drop(tx2);
select! {
_a1 = rx1.recv() => { panic!() },
a2 = rx2.recv() => { assert!(a2.is_err()); }
}
}
#[test]
fn unblocks() {
let (tx1, rx1) = channel::<i32>();
let (_tx2, rx2) = channel::<i32>();
let (tx3, rx3) = channel::<i32>();
let _t = thread::spawn(move|| {
for _ in 0..20 { thread::yield_now(); }
tx1.send(1).unwrap();
rx3.recv().unwrap();
for _ in 0..20 { thread::yield_now(); }
});
select! {
a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
_b = rx2.recv() => { panic!() }
}
tx3.send(1).unwrap();
select! {
a = rx1.recv() => { assert!(a.is_err()) },
_b = rx2.recv() => { panic!() }
}
}
#[test]
fn both_ready() {
let (tx1, rx1) = channel::<i32>();
let (tx2, rx2) = channel::<i32>();
let (tx3, rx3) = channel::<()>();
let _t = thread::spawn(move|| {
for _ in 0..20 { thread::yield_now(); }
tx1.send(1).unwrap();
tx2.send(2).unwrap();
rx3.recv().unwrap();
});
select! {
a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
a = rx2.recv() => { assert_eq!(a.unwrap(), 2); }
}
select! {
a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
a = rx2.recv() => { assert_eq!(a.unwrap(), 2); }
}
assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
assert_eq!(rx2.try_recv(), Err(TryRecvError::Empty));
tx3.send(()).unwrap();
}
#[test]
fn stress() {
const AMT: i32 = 10000;
let (tx1, rx1) = channel::<i32>();
let (tx2, rx2) = channel::<i32>();
let (tx3, rx3) = channel::<()>();
let _t = thread::spawn(move|| {
for i in 0..AMT {
if i % 2 == 0 {
tx1.send(i).unwrap();
} else {
tx2.send(i).unwrap();
}
rx3.recv().unwrap();
}
});
for i in 0..AMT {
select! {
i1 = rx1.recv() => { assert!(i % 2 == 0 && i == i1.unwrap()); },
i2 = rx2.recv() => { assert!(i % 2 == 1 && i == i2.unwrap()); }
}
tx3.send(()).unwrap();
}
}
#[allow(unused_must_use)]
#[test]
fn cloning() {
let (tx1, rx1) = channel::<i32>();
let (_tx2, rx2) = channel::<i32>();
let (tx3, rx3) = channel::<()>();
let _t = thread::spawn(move|| {
rx3.recv().unwrap();
tx1.clone();
assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty));
tx1.send(2).unwrap();
rx3.recv().unwrap();
});
tx3.send(()).unwrap();
select! {
_i1 = rx1.recv() => {},
_i2 = rx2.recv() => panic!()
}
tx3.send(()).unwrap();
}
#[allow(unused_must_use)]
#[test]
fn cloning2() {
let (tx1, rx1) = channel::<i32>();
let (_tx2, rx2) = channel::<i32>();
let (tx3, rx3) = channel::<()>();
let _t = thread::spawn(move|| {
rx3.recv().unwrap();
tx1.clone();
assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty));
tx1.send(2).unwrap();
rx3.recv().unwrap();
});
tx3.send(()).unwrap();
select! {
_i1 = rx1.recv() => {},
_i2 = rx2.recv() => panic!()
}
tx3.send(()).unwrap();
}
#[test]
fn cloning3() {
let (tx1, rx1) = channel::<()>();
let (tx2, rx2) = channel::<()>();
let (tx3, rx3) = channel::<()>();
let _t = thread::spawn(move|| {
let s = Select::new();
let mut h1 = s.handle(&rx1);
let mut h2 = s.handle(&rx2);
unsafe { h2.add(); }
unsafe { h1.add(); }
assert_eq!(s.wait(), h2.id);
tx3.send(()).unwrap();
});
for _ in 0..1000 { thread::yield_now(); }
drop(tx1.clone());
tx2.send(()).unwrap();
rx3.recv().unwrap();
}
#[test]
fn preflight1() {
let (tx, rx) = channel();
tx.send(()).unwrap();
select! {
_n = rx.recv() => {}
}
}
#[test]
fn preflight2() {
let (tx, rx) = channel();
tx.send(()).unwrap();
tx.send(()).unwrap();
select! {
_n = rx.recv() => {}
}
}
#[test]
fn preflight3() {
let (tx, rx) = channel();
drop(tx.clone());
tx.send(()).unwrap();
select! {
_n = rx.recv() => {}
}
}
#[test]
fn preflight4() {
let (tx, rx) = channel();
tx.send(()).unwrap();
let s = Select::new();
let mut h = s.handle(&rx);
unsafe { h.add(); }
assert_eq!(s.wait2(false), h.id);
}
#[test]
fn preflight5() {
let (tx, rx) = channel();
tx.send(()).unwrap();
tx.send(()).unwrap();
let s = Select::new();
let mut h = s.handle(&rx);
unsafe { h.add(); }
assert_eq!(s.wait2(false), h.id);
}
#[test]
fn preflight6() {
let (tx, rx) = channel();
drop(tx.clone());
tx.send(()).unwrap();
let s = Select::new();
let mut h = s.handle(&rx);
unsafe { h.add(); }
assert_eq!(s.wait2(false), h.id);
}
#[test]
fn preflight7() {
let (tx, rx) = channel::<()>();
drop(tx);
let s = Select::new();
let mut h = s.handle(&rx);
unsafe { h.add(); }
assert_eq!(s.wait2(false), h.id);
}
#[test]
fn preflight8() {
let (tx, rx) = channel();
tx.send(()).unwrap();
drop(tx);
rx.recv().unwrap();
let s = Select::new();
let mut h = s.handle(&rx);
unsafe { h.add(); }
assert_eq!(s.wait2(false), h.id);
}
#[test]
fn preflight9() {
let (tx, rx) = channel();
drop(tx.clone());
tx.send(()).unwrap();
drop(tx);
rx.recv().unwrap();
let s = Select::new();
let mut h = s.handle(&rx);
unsafe { h.add(); }
assert_eq!(s.wait2(false), h.id);
}
#[test]
fn oneshot_data_waiting() {
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
let _t = thread::spawn(move|| {
select! {
_n = rx1.recv() => {}
}
tx2.send(()).unwrap();
});
for _ in 0..100 { thread::yield_now() }
tx1.send(()).unwrap();
rx2.recv().unwrap();
}
#[test]
fn stream_data_waiting() {
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
tx1.send(()).unwrap();
tx1.send(()).unwrap();
rx1.recv().unwrap();
rx1.recv().unwrap();
let _t = thread::spawn(move|| {
select! {
_n = rx1.recv() => {}
}
tx2.send(()).unwrap();
});
for _ in 0..100 { thread::yield_now() }
tx1.send(()).unwrap();
rx2.recv().unwrap();
}
#[test]
fn shared_data_waiting() {
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
drop(tx1.clone());
tx1.send(()).unwrap();
rx1.recv().unwrap();
let _t = thread::spawn(move|| {
select! {
_n = rx1.recv() => {}
}
tx2.send(()).unwrap();
});
for _ in 0..100 { thread::yield_now() }
tx1.send(()).unwrap();
rx2.recv().unwrap();
}
#[test]
fn sync1() {
let (tx, rx) = sync_channel::<i32>(1);
tx.send(1).unwrap();
select! {
n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
}
}
#[test]
fn sync2() {
let (tx, rx) = sync_channel::<i32>(0);
let _t = thread::spawn(move|| {
for _ in 0..100 { thread::yield_now() }
tx.send(1).unwrap();
});
select! {
n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
}
}
#[test]
fn sync3() {
let (tx1, rx1) = sync_channel::<i32>(0);
let (tx2, rx2): (Sender<i32>, Receiver<i32>) = channel();
let _t = thread::spawn(move|| { tx1.send(1).unwrap(); });
let _t = thread::spawn(move|| { tx2.send(2).unwrap(); });
select! {
n = rx1.recv() => {
let n = n.unwrap();
assert_eq!(n, 1);
assert_eq!(rx2.recv().unwrap(), 2);
},
n = rx2.recv() => {
let n = n.unwrap();
assert_eq!(n, 2);
assert_eq!(rx1.recv().unwrap(), 1);
}
}
}
}