2012-08-14 19:25:42 -04:00
|
|
|
// NB: transitionary, de-mode-ing.
|
|
|
|
#[forbid(deprecated_mode)];
|
|
|
|
#[forbid(deprecated_pattern)];
|
2012-07-04 22:53:12 +01:00
|
|
|
/*!
|
|
|
|
* Communication between tasks
|
|
|
|
*
|
|
|
|
* Communication between tasks is facilitated by ports (in the receiving
|
|
|
|
* task), and channels (in the sending task). Any number of channels may
|
|
|
|
* feed into a single port. Ports and channels may only transmit values
|
|
|
|
* of unique types; that is, values that are statically guaranteed to be
|
|
|
|
* accessed by a single 'owner' at a time. Unique types include scalars,
|
|
|
|
* vectors, strings, and records, tags, tuples and unique boxes (`~T`)
|
|
|
|
* thereof. Most notably, shared boxes (`@T`) may not be transmitted
|
|
|
|
* across channels.
|
|
|
|
*
|
|
|
|
* # Example
|
|
|
|
*
|
|
|
|
* ~~~
|
|
|
|
* let po = comm::port();
|
|
|
|
* let ch = comm::chan(po);
|
|
|
|
*
|
2012-07-09 13:46:32 +02:00
|
|
|
* do task::spawn {
|
2012-07-04 22:53:12 +01:00
|
|
|
* comm::send(ch, "Hello, World");
|
2012-07-09 13:46:32 +02:00
|
|
|
* }
|
2012-07-04 22:53:12 +01:00
|
|
|
*
|
|
|
|
* io::println(comm::recv(p));
|
|
|
|
* ~~~
|
|
|
|
*/
|
2011-12-13 16:25:51 -08:00
|
|
|
|
2012-09-04 11:12:17 -07:00
|
|
|
use either::Either;
|
|
|
|
use libc::size_t;
|
2011-12-13 16:25:51 -08:00
|
|
|
|
2012-08-27 14:22:25 -07:00
|
|
|
export Port;
|
|
|
|
export Chan;
|
2011-12-13 16:25:51 -08:00
|
|
|
export send;
|
|
|
|
export recv;
|
2012-02-14 14:07:06 -08:00
|
|
|
export peek;
|
2012-05-01 23:20:51 -07:00
|
|
|
export recv_chan;
|
2012-02-14 22:25:05 -08:00
|
|
|
export select2;
|
2012-05-02 00:04:53 -07:00
|
|
|
export methods;
|
2012-05-02 00:55:40 -07:00
|
|
|
export listen;
|
2011-12-13 16:25:51 -08:00
|
|
|
|
2012-02-01 11:45:23 +01:00
|
|
|
|
2012-07-04 22:53:12 +01:00
|
|
|
/**
|
|
|
|
* A communication endpoint that can receive messages
|
|
|
|
*
|
|
|
|
* Each port has a unique per-task identity and may not be replicated or
|
|
|
|
* transmitted. If a port value is copied, both copies refer to the same
|
|
|
|
* port. Ports may be associated with multiple `chan`s.
|
|
|
|
*/
|
2012-08-15 14:10:46 -07:00
|
|
|
enum Port<T: send> {
|
|
|
|
Port_(@PortPtr<T>)
|
2011-12-13 16:25:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// It's critical that this only have one variant, so it has a record
|
|
|
|
// layout, and will work in the rust_task structure in task.rs.
|
2012-07-04 22:53:12 +01:00
|
|
|
/**
|
|
|
|
* A communication endpoint that can send messages
|
|
|
|
*
|
|
|
|
* Each channel is bound to a port when the channel is constructed, so
|
|
|
|
* the destination port for a channel must exist before the channel
|
|
|
|
* itself. Channels are weak: a channel does not keep the port it is
|
|
|
|
* bound to alive. If a channel attempts to send data to a dead port that
|
|
|
|
* data will be silently dropped. Channels may be duplicated and
|
|
|
|
* themselves transmitted over other channels.
|
|
|
|
*/
|
2012-08-15 14:10:46 -07:00
|
|
|
enum Chan<T: send> {
|
|
|
|
Chan_(port_id)
|
2011-12-13 16:25:51 -08:00
|
|
|
}
|
|
|
|
|
2012-07-04 22:53:12 +01:00
|
|
|
/// Constructs a port
|
2012-08-27 14:22:25 -07:00
|
|
|
fn Port<T: send>() -> Port<T> {
|
2012-08-15 14:10:46 -07:00
|
|
|
Port_(@PortPtr(rustrt::new_port(sys::size_of::<T>() as size_t)))
|
2011-12-13 16:25:51 -08:00
|
|
|
}
|
|
|
|
|
2012-08-15 14:10:46 -07:00
|
|
|
impl<T: send> Port<T> {
|
2012-05-02 00:04:53 -07:00
|
|
|
|
2012-08-27 14:22:25 -07:00
|
|
|
fn chan() -> Chan<T> { Chan(self) }
|
2012-05-02 00:04:53 -07:00
|
|
|
fn send(+v: T) { self.chan().send(v) }
|
|
|
|
fn recv() -> T { recv(self) }
|
|
|
|
fn peek() -> bool { peek(self) }
|
2011-12-13 16:25:51 -08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-08-15 14:10:46 -07:00
|
|
|
impl<T: send> Chan<T> {
|
2012-05-02 00:04:53 -07:00
|
|
|
|
2012-08-15 14:10:46 -07:00
|
|
|
fn chan() -> Chan<T> { self }
|
2012-05-02 00:04:53 -07:00
|
|
|
fn send(+v: T) { send(self, v) }
|
|
|
|
fn recv() -> T { recv_chan(self) }
|
|
|
|
fn peek() -> bool { peek_chan(self) }
|
2011-12-13 16:25:51 -08:00
|
|
|
|
2012-05-01 23:20:51 -07:00
|
|
|
}
|
|
|
|
|
2012-07-04 22:53:12 +01:00
|
|
|
/// Open a new receiving channel for the duration of a function
|
2012-08-15 14:10:46 -07:00
|
|
|
fn listen<T: send, U>(f: fn(Chan<T>) -> U) -> U {
|
2012-08-27 14:22:25 -07:00
|
|
|
let po = Port();
|
2012-05-02 00:55:40 -07:00
|
|
|
f(po.chan())
|
|
|
|
}
|
|
|
|
|
2012-08-15 18:46:55 -07:00
|
|
|
struct PortPtr<T:send> {
|
2012-06-18 13:49:20 -07:00
|
|
|
let po: *rust_port;
|
|
|
|
new(po: *rust_port) { self.po = po; }
|
|
|
|
drop unsafe {
|
2012-07-04 15:04:28 -04:00
|
|
|
do task::unkillable {
|
2012-05-15 11:51:24 -07:00
|
|
|
// Once the port is detached it's guaranteed not to receive further
|
|
|
|
// messages
|
|
|
|
let yield = 0u;
|
|
|
|
let yieldp = ptr::addr_of(yield);
|
2012-06-18 13:49:20 -07:00
|
|
|
rustrt::rust_port_begin_detach(self.po, yieldp);
|
2012-05-15 11:51:24 -07:00
|
|
|
if yield != 0u {
|
|
|
|
// Need to wait for the port to be detached
|
|
|
|
task::yield();
|
|
|
|
}
|
2012-06-18 13:49:20 -07:00
|
|
|
rustrt::rust_port_end_detach(self.po);
|
2012-05-01 23:20:51 -07:00
|
|
|
|
2012-05-15 11:51:24 -07:00
|
|
|
// Drain the port so that all the still-enqueued items get dropped
|
2012-06-18 13:49:20 -07:00
|
|
|
while rustrt::rust_port_size(self.po) > 0u as size_t {
|
|
|
|
recv_::<T>(self.po);
|
2012-05-15 11:51:24 -07:00
|
|
|
}
|
2012-06-18 13:49:20 -07:00
|
|
|
rustrt::del_port(self.po);
|
2012-05-01 23:20:51 -07:00
|
|
|
}
|
2012-06-18 13:49:20 -07:00
|
|
|
}
|
2012-05-01 23:20:51 -07:00
|
|
|
}
|
|
|
|
|
2012-07-04 22:53:12 +01:00
|
|
|
/**
|
|
|
|
* Internal function for converting from a channel to a port
|
|
|
|
*
|
|
|
|
* # Failure
|
|
|
|
*
|
|
|
|
* Fails if the port is detached or dead. Fails if the port
|
|
|
|
* is owned by a different task.
|
|
|
|
*/
|
2012-08-15 14:10:46 -07:00
|
|
|
fn as_raw_port<T: send, U>(ch: comm::Chan<T>, f: fn(*rust_port) -> U) -> U {
|
2012-06-18 13:49:20 -07:00
|
|
|
|
2012-08-15 18:46:55 -07:00
|
|
|
struct PortRef {
|
2012-06-18 13:49:20 -07:00
|
|
|
let p: *rust_port;
|
|
|
|
new(p: *rust_port) { self.p = p; }
|
|
|
|
drop {
|
|
|
|
if !ptr::is_null(self.p) {
|
|
|
|
rustrt::rust_port_drop(self.p);
|
|
|
|
}
|
|
|
|
}
|
2012-05-01 17:39:56 -07:00
|
|
|
}
|
|
|
|
|
2012-08-15 14:10:46 -07:00
|
|
|
let p = PortRef(rustrt::rust_port_take(*ch));
|
2012-05-01 17:39:56 -07:00
|
|
|
|
2012-06-18 13:49:20 -07:00
|
|
|
if ptr::is_null(p.p) {
|
2012-07-13 22:57:48 -07:00
|
|
|
fail ~"unable to locate port for channel"
|
2012-06-18 13:49:20 -07:00
|
|
|
} else if rustrt::get_task_id() != rustrt::rust_port_task(p.p) {
|
2012-07-13 22:57:48 -07:00
|
|
|
fail ~"unable to access unowned port"
|
2012-05-01 17:39:56 -07:00
|
|
|
}
|
|
|
|
|
2012-06-18 13:49:20 -07:00
|
|
|
f(p.p)
|
2012-05-02 00:04:53 -07:00
|
|
|
}
|
|
|
|
|
2012-07-04 22:53:12 +01:00
|
|
|
/**
|
|
|
|
* Constructs a channel. The channel is bound to the port used to
|
|
|
|
* construct it.
|
|
|
|
*/
|
2012-08-27 14:22:25 -07:00
|
|
|
fn Chan<T: send>(p: Port<T>) -> Chan<T> {
|
2012-08-15 14:10:46 -07:00
|
|
|
Chan_(rustrt::get_port_id((**p).po))
|
2012-05-02 00:04:53 -07:00
|
|
|
}
|
|
|
|
|
2012-07-04 22:53:12 +01:00
|
|
|
/**
|
|
|
|
* Sends data over a channel. The sent data is moved into the channel,
|
|
|
|
* whereupon the caller loses access to it.
|
|
|
|
*/
|
2012-08-15 14:10:46 -07:00
|
|
|
fn send<T: send>(ch: Chan<T>, +data: T) {
|
|
|
|
let Chan_(p) = ch;
|
2012-06-01 19:47:04 -07:00
|
|
|
let data_ptr = ptr::addr_of(data) as *();
|
|
|
|
let res = rustrt::rust_port_id_send(p, data_ptr);
|
2012-05-02 00:04:53 -07:00
|
|
|
if res != 0u unsafe {
|
|
|
|
// Data sent successfully
|
|
|
|
unsafe::forget(data);
|
|
|
|
}
|
|
|
|
task::yield();
|
|
|
|
}
|
|
|
|
|
2012-07-04 22:53:12 +01:00
|
|
|
/**
|
|
|
|
* Receive from a port. If no data is available on the port then the
|
|
|
|
* task will block until data becomes available.
|
|
|
|
*/
|
2012-08-15 14:10:46 -07:00
|
|
|
fn recv<T: send>(p: Port<T>) -> T { recv_((**p).po) }
|
2012-05-02 00:04:53 -07:00
|
|
|
|
2012-07-04 22:53:12 +01:00
|
|
|
/// Returns true if there are messages available
|
2012-08-15 14:10:46 -07:00
|
|
|
fn peek<T: send>(p: Port<T>) -> bool { peek_((**p).po) }
|
2012-05-02 00:04:53 -07:00
|
|
|
|
|
|
|
#[doc(hidden)]
|
2012-08-15 14:10:46 -07:00
|
|
|
fn recv_chan<T: send>(ch: comm::Chan<T>) -> T {
|
2012-06-30 16:19:07 -07:00
|
|
|
as_raw_port(ch, |x|recv_(x))
|
2012-05-02 00:04:53 -07:00
|
|
|
}
|
|
|
|
|
2012-08-15 14:10:46 -07:00
|
|
|
fn peek_chan<T: send>(ch: comm::Chan<T>) -> bool {
|
2012-06-30 16:19:07 -07:00
|
|
|
as_raw_port(ch, |x|peek_(x))
|
2012-05-01 17:39:56 -07:00
|
|
|
}
|
|
|
|
|
2012-07-04 22:53:12 +01:00
|
|
|
/// Receive on a raw port pointer
|
2012-02-01 11:45:23 +01:00
|
|
|
fn recv_<T: send>(p: *rust_port) -> T {
|
2011-12-13 16:25:51 -08:00
|
|
|
let yield = 0u;
|
|
|
|
let yieldp = ptr::addr_of(yield);
|
2012-03-22 12:30:10 +01:00
|
|
|
let mut res;
|
|
|
|
res = rusti::init::<T>();
|
|
|
|
rustrt::port_recv(ptr::addr_of(res) as *uint, p, yieldp);
|
|
|
|
|
2011-12-13 16:25:51 -08:00
|
|
|
if yield != 0u {
|
|
|
|
// Data isn't available yet, so res has not been initialized.
|
|
|
|
task::yield();
|
2012-03-02 00:31:14 -08:00
|
|
|
} else {
|
2012-06-18 13:49:20 -07:00
|
|
|
// In the absence of compiler-generated preemption points
|
2012-03-02 00:31:14 -08:00
|
|
|
// this is a good place to yield
|
|
|
|
task::yield();
|
2011-12-13 16:25:51 -08:00
|
|
|
}
|
2012-08-01 17:30:05 -07:00
|
|
|
return res;
|
2011-12-13 16:25:51 -08:00
|
|
|
}
|
|
|
|
|
2012-06-24 20:18:18 -07:00
|
|
|
fn peek_(p: *rust_port) -> bool {
|
2012-07-17 23:13:11 -05:00
|
|
|
// Yield here before we check to see if someone sent us a message
|
|
|
|
// FIXME #524, if the compilergenerates yields, we don't need this
|
|
|
|
task::yield();
|
2012-05-02 00:04:53 -07:00
|
|
|
rustrt::rust_port_size(p) != 0u as libc::size_t
|
|
|
|
}
|
|
|
|
|
2012-07-04 22:53:12 +01:00
|
|
|
/// Receive on one of two ports
|
2012-08-15 14:10:46 -07:00
|
|
|
fn select2<A: send, B: send>(p_a: Port<A>, p_b: Port<B>)
|
2012-08-14 16:54:13 -07:00
|
|
|
-> Either<A, B> {
|
2012-06-29 16:26:56 -07:00
|
|
|
let ports = ~[(**p_a).po, (**p_b).po];
|
2012-03-22 12:30:10 +01:00
|
|
|
let yield = 0u, yieldp = ptr::addr_of(yield);
|
2012-02-14 22:25:05 -08:00
|
|
|
|
2012-03-22 12:30:10 +01:00
|
|
|
let mut resport: *rust_port;
|
|
|
|
resport = rusti::init::<*rust_port>();
|
2012-07-24 12:35:34 -07:00
|
|
|
do vec::as_buf(ports) |ports, n_ports| {
|
|
|
|
rustrt::rust_port_select(ptr::addr_of(resport), ports,
|
|
|
|
n_ports as size_t, yieldp);
|
2012-03-22 12:30:10 +01:00
|
|
|
}
|
2012-02-14 22:25:05 -08:00
|
|
|
|
|
|
|
if yield != 0u {
|
|
|
|
// Wait for data
|
|
|
|
task::yield();
|
2012-03-02 00:31:14 -08:00
|
|
|
} else {
|
|
|
|
// As in recv, this is a good place to yield anyway until
|
|
|
|
// the compiler generates yield calls
|
|
|
|
task::yield();
|
2012-02-14 22:25:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now we know the port we're supposed to receive from
|
|
|
|
assert resport != ptr::null();
|
|
|
|
|
2012-06-18 13:49:20 -07:00
|
|
|
if resport == (**p_a).po {
|
2012-08-14 16:54:13 -07:00
|
|
|
either::Left(recv(p_a))
|
2012-06-18 13:49:20 -07:00
|
|
|
} else if resport == (**p_b).po {
|
2012-08-14 16:54:13 -07:00
|
|
|
either::Right(recv(p_b))
|
2012-02-14 22:25:05 -08:00
|
|
|
} else {
|
2012-07-13 22:57:48 -07:00
|
|
|
fail ~"unexpected result from rust_port_select";
|
2012-02-14 22:25:05 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-01 23:20:51 -07:00
|
|
|
|
|
|
|
/* Implementation details */
|
|
|
|
|
2012-08-15 14:10:46 -07:00
|
|
|
#[allow(non_camel_case_types)] // runtime type
|
2012-05-01 23:20:51 -07:00
|
|
|
enum rust_port {}
|
|
|
|
|
2012-08-15 14:10:46 -07:00
|
|
|
#[allow(non_camel_case_types)] // runtime type
|
2012-05-01 23:20:51 -07:00
|
|
|
type port_id = int;
|
|
|
|
|
|
|
|
#[abi = "cdecl"]
|
2012-07-03 16:11:00 -07:00
|
|
|
extern mod rustrt {
|
2012-06-01 19:47:04 -07:00
|
|
|
fn rust_port_id_send(target_port: port_id, data: *()) -> libc::uintptr_t;
|
2012-05-01 23:20:51 -07:00
|
|
|
|
|
|
|
fn new_port(unit_sz: libc::size_t) -> *rust_port;
|
|
|
|
fn del_port(po: *rust_port);
|
|
|
|
fn rust_port_begin_detach(po: *rust_port,
|
|
|
|
yield: *libc::uintptr_t);
|
|
|
|
fn rust_port_end_detach(po: *rust_port);
|
|
|
|
fn get_port_id(po: *rust_port) -> port_id;
|
|
|
|
fn rust_port_size(po: *rust_port) -> libc::size_t;
|
|
|
|
fn port_recv(dptr: *uint, po: *rust_port,
|
|
|
|
yield: *libc::uintptr_t);
|
|
|
|
fn rust_port_select(dptr: **rust_port, ports: **rust_port,
|
|
|
|
n_ports: libc::size_t,
|
|
|
|
yield: *libc::uintptr_t);
|
|
|
|
fn rust_port_take(port_id: port_id) -> *rust_port;
|
|
|
|
fn rust_port_drop(p: *rust_port);
|
|
|
|
fn rust_port_task(p: *rust_port) -> libc::uintptr_t;
|
|
|
|
fn get_task_id() -> libc::uintptr_t;
|
2012-02-14 14:07:06 -08:00
|
|
|
}
|
|
|
|
|
2012-05-01 23:20:51 -07:00
|
|
|
#[abi = "rust-intrinsic"]
|
2012-07-03 16:11:00 -07:00
|
|
|
extern mod rusti {
|
2012-05-01 23:20:51 -07:00
|
|
|
fn init<T>() -> T;
|
2011-12-13 16:25:51 -08:00
|
|
|
}
|
2012-01-17 17:28:21 -08:00
|
|
|
|
2012-05-01 23:20:51 -07:00
|
|
|
|
|
|
|
/* Tests */
|
|
|
|
|
|
|
|
|
2012-01-17 17:28:21 -08:00
|
|
|
#[test]
|
2012-08-27 14:22:25 -07:00
|
|
|
fn create_port_and_chan() { let p = Port::<int>(); Chan(p); }
|
2012-01-17 17:28:21 -08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn send_int() {
|
2012-08-27 14:22:25 -07:00
|
|
|
let p = Port::<int>();
|
|
|
|
let c = Chan(p);
|
2012-01-17 17:28:21 -08:00
|
|
|
send(c, 22);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn send_recv_fn() {
|
2012-08-27 14:22:25 -07:00
|
|
|
let p = Port::<int>();
|
|
|
|
let c = Chan::<int>(p);
|
2012-01-17 17:28:21 -08:00
|
|
|
send(c, 42);
|
|
|
|
assert (recv(p) == 42);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn send_recv_fn_infer() {
|
2012-08-27 14:22:25 -07:00
|
|
|
let p = Port();
|
|
|
|
let c = Chan(p);
|
2012-01-17 17:28:21 -08:00
|
|
|
send(c, 42);
|
|
|
|
assert (recv(p) == 42);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn chan_chan_infer() {
|
2012-08-27 14:22:25 -07:00
|
|
|
let p = Port(), p2 = Port::<int>();
|
|
|
|
let c = Chan(p);
|
|
|
|
send(c, Chan(p2));
|
2012-01-17 17:28:21 -08:00
|
|
|
recv(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn chan_chan() {
|
2012-08-27 14:22:25 -07:00
|
|
|
let p = Port::<Chan<int>>(), p2 = Port::<int>();
|
|
|
|
let c = Chan(p);
|
|
|
|
send(c, Chan(p2));
|
2012-01-17 17:28:21 -08:00
|
|
|
recv(p);
|
|
|
|
}
|
|
|
|
|
2012-02-14 14:07:06 -08:00
|
|
|
#[test]
|
|
|
|
fn test_peek() {
|
2012-08-27 14:22:25 -07:00
|
|
|
let po = Port();
|
|
|
|
let ch = Chan(po);
|
2012-02-14 14:07:06 -08:00
|
|
|
assert !peek(po);
|
|
|
|
send(ch, ());
|
|
|
|
assert peek(po);
|
|
|
|
recv(po);
|
|
|
|
assert !peek(po);
|
2012-02-14 22:25:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_select2_available() {
|
2012-08-27 14:22:25 -07:00
|
|
|
let po_a = Port();
|
|
|
|
let po_b = Port();
|
|
|
|
let ch_a = Chan(po_a);
|
|
|
|
let ch_b = Chan(po_b);
|
2012-02-14 22:25:05 -08:00
|
|
|
|
2012-07-13 22:57:48 -07:00
|
|
|
send(ch_a, ~"a");
|
2012-02-14 22:25:05 -08:00
|
|
|
|
2012-08-14 16:54:13 -07:00
|
|
|
assert select2(po_a, po_b) == either::Left(~"a");
|
2012-02-14 22:25:05 -08:00
|
|
|
|
2012-07-13 22:57:48 -07:00
|
|
|
send(ch_b, ~"b");
|
2012-02-14 22:25:05 -08:00
|
|
|
|
2012-08-14 16:54:13 -07:00
|
|
|
assert select2(po_a, po_b) == either::Right(~"b");
|
2012-02-14 22:25:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_select2_rendezvous() {
|
2012-08-27 14:22:25 -07:00
|
|
|
let po_a = Port();
|
|
|
|
let po_b = Port();
|
|
|
|
let ch_a = Chan(po_a);
|
|
|
|
let ch_b = Chan(po_b);
|
2012-02-14 22:25:05 -08:00
|
|
|
|
2012-07-04 15:04:28 -04:00
|
|
|
for iter::repeat(10u) {
|
|
|
|
do task::spawn {
|
2012-07-03 16:46:57 -07:00
|
|
|
for iter::repeat(10u) { task::yield() }
|
2012-07-13 22:57:48 -07:00
|
|
|
send(ch_a, ~"a");
|
2012-02-14 22:25:05 -08:00
|
|
|
};
|
|
|
|
|
2012-08-14 16:54:13 -07:00
|
|
|
assert select2(po_a, po_b) == either::Left(~"a");
|
2012-02-14 22:25:05 -08:00
|
|
|
|
2012-07-04 15:04:28 -04:00
|
|
|
do task::spawn {
|
2012-07-03 16:46:57 -07:00
|
|
|
for iter::repeat(10u) { task::yield() }
|
2012-07-13 22:57:48 -07:00
|
|
|
send(ch_b, ~"b");
|
2012-02-14 22:25:05 -08:00
|
|
|
};
|
|
|
|
|
2012-08-14 16:54:13 -07:00
|
|
|
assert select2(po_a, po_b) == either::Right(~"b");
|
2012-02-14 22:25:05 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_select2_stress() {
|
2012-08-27 14:22:25 -07:00
|
|
|
let po_a = Port();
|
|
|
|
let po_b = Port();
|
|
|
|
let ch_a = Chan(po_a);
|
|
|
|
let ch_b = Chan(po_b);
|
2012-02-14 22:25:05 -08:00
|
|
|
|
|
|
|
let msgs = 100u;
|
|
|
|
let times = 4u;
|
|
|
|
|
2012-07-04 15:04:28 -04:00
|
|
|
for iter::repeat(times) {
|
|
|
|
do task::spawn {
|
|
|
|
for iter::repeat(msgs) {
|
2012-07-13 22:57:48 -07:00
|
|
|
send(ch_a, ~"a")
|
2012-02-14 22:25:05 -08:00
|
|
|
}
|
|
|
|
};
|
2012-07-04 15:04:28 -04:00
|
|
|
do task::spawn {
|
|
|
|
for iter::repeat(msgs) {
|
2012-07-13 22:57:48 -07:00
|
|
|
send(ch_b, ~"b")
|
2012-02-14 22:25:05 -08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2012-03-22 08:39:41 -07:00
|
|
|
let mut as = 0;
|
|
|
|
let mut bs = 0;
|
2012-07-04 15:04:28 -04:00
|
|
|
for iter::repeat(msgs * times * 2u) {
|
2012-08-15 11:55:17 -07:00
|
|
|
match select2(po_a, po_b) {
|
2012-08-14 16:54:13 -07:00
|
|
|
either::Left(~"a") => as += 1,
|
|
|
|
either::Right(~"b") => bs += 1,
|
2012-08-15 11:55:17 -07:00
|
|
|
_ => fail ~"test_select_2_stress failed"
|
2012-02-14 22:25:05 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert as == 400;
|
|
|
|
assert bs == 400;
|
|
|
|
}
|
2012-05-01 17:39:56 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_recv_chan() {
|
2012-08-27 14:22:25 -07:00
|
|
|
let po = Port();
|
|
|
|
let ch = Chan(po);
|
2012-07-13 22:57:48 -07:00
|
|
|
send(ch, ~"flower");
|
|
|
|
assert recv_chan(ch) == ~"flower";
|
2012-05-01 17:39:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_fail]
|
2012-06-07 21:38:25 -07:00
|
|
|
#[ignore(cfg(windows))]
|
2012-05-01 17:39:56 -07:00
|
|
|
fn test_recv_chan_dead() {
|
2012-08-27 14:22:25 -07:00
|
|
|
let ch = Chan(Port());
|
2012-07-13 22:57:48 -07:00
|
|
|
send(ch, ~"flower");
|
2012-05-01 17:39:56 -07:00
|
|
|
recv_chan(ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2012-06-07 21:38:25 -07:00
|
|
|
#[ignore(cfg(windows))]
|
2012-05-01 17:39:56 -07:00
|
|
|
fn test_recv_chan_wrong_task() {
|
2012-08-27 14:22:25 -07:00
|
|
|
let po = Port();
|
|
|
|
let ch = Chan(po);
|
2012-07-13 22:57:48 -07:00
|
|
|
send(ch, ~"flower");
|
2012-06-30 16:19:07 -07:00
|
|
|
assert result::is_err(task::try(||
|
2012-05-01 17:39:56 -07:00
|
|
|
recv_chan(ch)
|
2012-06-30 16:19:07 -07:00
|
|
|
))
|
2012-05-01 17:39:56 -07:00
|
|
|
}
|
2012-05-02 00:04:53 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_port_send() {
|
2012-08-27 14:22:25 -07:00
|
|
|
let po = Port();
|
2012-05-02 00:04:53 -07:00
|
|
|
po.send(());
|
|
|
|
po.recv();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_chan_peek() {
|
2012-08-27 14:22:25 -07:00
|
|
|
let po = Port();
|
2012-05-02 00:04:53 -07:00
|
|
|
let ch = po.chan();
|
|
|
|
ch.send(());
|
|
|
|
assert ch.peek();
|
2012-05-02 00:55:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_listen() {
|
2012-06-30 16:19:07 -07:00
|
|
|
do listen |parent| {
|
2012-07-04 15:04:28 -04:00
|
|
|
do task::spawn {
|
2012-07-13 22:57:48 -07:00
|
|
|
parent.send(~"oatmeal-salad");
|
2012-05-02 00:55:40 -07:00
|
|
|
}
|
2012-07-13 22:57:48 -07:00
|
|
|
assert parent.recv() == ~"oatmeal-salad";
|
2012-05-02 00:55:40 -07:00
|
|
|
}
|
2012-05-15 11:51:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2012-06-07 21:38:25 -07:00
|
|
|
#[ignore(cfg(windows))]
|
2012-05-15 11:51:24 -07:00
|
|
|
fn test_port_detach_fail() {
|
2012-07-04 15:04:28 -04:00
|
|
|
for iter::repeat(100u) {
|
2012-07-23 15:53:18 -04:00
|
|
|
do task::spawn_unlinked {
|
2012-08-27 14:22:25 -07:00
|
|
|
let po = Port();
|
2012-05-15 11:51:24 -07:00
|
|
|
let ch = po.chan();
|
|
|
|
|
2012-07-04 15:04:28 -04:00
|
|
|
do task::spawn {
|
2012-05-15 11:51:24 -07:00
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
2012-07-04 15:04:28 -04:00
|
|
|
do task::spawn {
|
2012-05-15 11:51:24 -07:00
|
|
|
ch.send(());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-06-18 13:49:20 -07:00
|
|
|
}
|