auto merge of #8170 : brson/rust/nopipes, r=pcwalton
The pipes compiler produced data types that encoded efficient and safe bounded message passing protocols between two endpoints. It was also capable of producing unbounded protocols. It was useful research but was arguably done before its proper time. I am removing it for the following reasons: * In practice we used it only for producing the `oneshot` protcol and the unbounded `stream` protocol and all communication in Rust use those. * The interface between the proto! macro and the standard library has a large surface area and was difficult to maintain through language and library changes. * It is now written in an old dialect of Rust and generates code which would likely be considered non-idiomatic. * Both the compiler and the runtime are difficult to understand, and likewise the relationship between the generated code and the library is hard to understand. Debugging is difficult. * The new scheduler implements `stream` and `oneshot` by hand in a way that will be significantly easier to maintain. This shouldn't be taken as an indication that 'channel protocols' for Rust are not worth pursuing again in the future. Concerned parties may include: @graydon, @pcwalton, @eholk, @bblum The most likely candidates for closing are #7666, #3018, #3020, #7021, #7667, #7303, #3658, #3295.
This commit is contained in:
commit
eb5743bfb2
23 changed files with 3 additions and 2369 deletions
|
|
@ -1,111 +0,0 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// This test creates a bunch of tasks that simultaneously send to each
|
||||
// other in a ring. The messages should all be basically
|
||||
// independent. It's designed to hammer the global kernel lock, so
|
||||
// that things will look really good once we get that lock out of the
|
||||
// message path.
|
||||
|
||||
// This version uses automatically compiled channel contracts.
|
||||
|
||||
extern mod extra;
|
||||
|
||||
use extra::future;
|
||||
use extra::time;
|
||||
use std::cell::Cell;
|
||||
use std::io;
|
||||
use std::os;
|
||||
use std::pipes::recv;
|
||||
use std::uint;
|
||||
use std::util;
|
||||
|
||||
proto! ring (
|
||||
num:send {
|
||||
num(uint) -> num
|
||||
}
|
||||
)
|
||||
|
||||
fn thread_ring(i: uint,
|
||||
count: uint,
|
||||
num_chan: ring::client::num,
|
||||
num_port: ring::server::num) {
|
||||
let mut num_chan = Some(num_chan);
|
||||
let mut num_port = Some(num_port);
|
||||
// Send/Receive lots of messages.
|
||||
for uint::range(0, count) |j| {
|
||||
//error!("task %?, iter %?", i, j);
|
||||
let num_chan2 = util::replace(&mut num_chan, None);
|
||||
let num_port2 = util::replace(&mut num_port, None);
|
||||
num_chan = Some(ring::client::num(num_chan2.unwrap(), i * j));
|
||||
let port = num_port2.unwrap();
|
||||
match recv(port) {
|
||||
ring::num(_n, p) => {
|
||||
//log(error, _n);
|
||||
num_port = Some(p);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = os::args();
|
||||
let args = if os::getenv("RUST_BENCH").is_some() {
|
||||
~[~"", ~"100", ~"10000"]
|
||||
} else if args.len() <= 1u {
|
||||
~[~"", ~"100", ~"1000"]
|
||||
} else {
|
||||
args.clone()
|
||||
};
|
||||
|
||||
let num_tasks = uint::from_str(args[1]).get();
|
||||
let msg_per_task = uint::from_str(args[2]).get();
|
||||
|
||||
let (num_port, num_chan) = ring::init();
|
||||
let num_chan = Cell::new(num_chan);
|
||||
|
||||
let start = time::precise_time_s();
|
||||
|
||||
// create the ring
|
||||
let mut futures = ~[];
|
||||
|
||||
for uint::range(1u, num_tasks) |i| {
|
||||
//error!("spawning %?", i);
|
||||
let (num_port, new_chan) = ring::init();
|
||||
let num_chan2 = Cell::new(num_chan.take());
|
||||
let num_port = Cell::new(num_port);
|
||||
let new_future = do future::spawn || {
|
||||
let num_chan = num_chan2.take();
|
||||
let num_port1 = num_port.take();
|
||||
thread_ring(i, msg_per_task, num_chan, num_port1)
|
||||
};
|
||||
futures.push(new_future);
|
||||
num_chan.put_back(new_chan);
|
||||
};
|
||||
|
||||
// do our iteration
|
||||
thread_ring(0, msg_per_task, num_chan.take(), num_port);
|
||||
|
||||
// synchronize
|
||||
foreach f in futures.mut_iter() {
|
||||
let _ = f.get();
|
||||
}
|
||||
|
||||
let stop = time::precise_time_s();
|
||||
|
||||
// all done, report stats.
|
||||
let num_msgs = num_tasks * msg_per_task;
|
||||
let elapsed = (stop - start);
|
||||
let rate = (num_msgs as float) / elapsed;
|
||||
|
||||
printfln!("Sent %? messages in %? seconds", num_msgs, elapsed);
|
||||
printfln!(" %? messages / second", rate);
|
||||
printfln!(" %? μs / message", 1000000. / rate);
|
||||
}
|
||||
|
|
@ -1,210 +0,0 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Compare bounded and unbounded protocol performance.
|
||||
|
||||
// xfail-pretty
|
||||
|
||||
extern mod extra;
|
||||
|
||||
use extra::time::precise_time_s;
|
||||
use std::cell::Cell;
|
||||
use std::io;
|
||||
use std::os;
|
||||
use std::pipes::*;
|
||||
use std::task;
|
||||
|
||||
proto! pingpong (
|
||||
ping: send {
|
||||
ping -> pong
|
||||
}
|
||||
|
||||
pong: recv {
|
||||
pong -> ping
|
||||
}
|
||||
)
|
||||
|
||||
proto! pingpong_unbounded (
|
||||
ping: send {
|
||||
ping -> pong
|
||||
}
|
||||
|
||||
pong: recv {
|
||||
pong -> ping
|
||||
}
|
||||
|
||||
you_will_never_catch_me: send {
|
||||
never_ever_ever -> you_will_never_catch_me
|
||||
}
|
||||
)
|
||||
|
||||
// This stuff should go in libcore::pipes
|
||||
macro_rules! move_it (
|
||||
{ $x:expr } => { let t = *ptr::to_unsafe_ptr(&($x)); t }
|
||||
)
|
||||
|
||||
macro_rules! follow (
|
||||
{
|
||||
$($message:path($($x: ident),+) -> $next:ident $e:expr)+
|
||||
} => (
|
||||
|m| match m {
|
||||
$(Some($message($($x,)* next)) => {
|
||||
let $next = next;
|
||||
$e })+
|
||||
_ => { fail!() }
|
||||
}
|
||||
);
|
||||
|
||||
{
|
||||
$($message:path -> $next:ident $e:expr)+
|
||||
} => (
|
||||
|m| match m {
|
||||
$(Some($message(next)) => {
|
||||
let $next = next;
|
||||
$e })+
|
||||
_ => { fail!() }
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
/** Spawn a task to provide a service.
|
||||
|
||||
It takes an initialization function that produces a send and receive
|
||||
endpoint. The send endpoint is returned to the caller and the receive
|
||||
endpoint is passed to the new task.
|
||||
|
||||
*/
|
||||
pub fn spawn_service<T:Send,Tb:Send>(
|
||||
init: extern fn() -> (RecvPacketBuffered<T, Tb>,
|
||||
SendPacketBuffered<T, Tb>),
|
||||
service: ~fn(v: RecvPacketBuffered<T, Tb>))
|
||||
-> SendPacketBuffered<T, Tb> {
|
||||
let (server, client) = init();
|
||||
|
||||
// This is some nasty gymnastics required to safely move the pipe
|
||||
// into a new task.
|
||||
let server = Cell::new(server);
|
||||
do task::spawn {
|
||||
service(server.take());
|
||||
}
|
||||
|
||||
client
|
||||
}
|
||||
|
||||
/** Like `spawn_service_recv`, but for protocols that start in the
|
||||
receive state.
|
||||
|
||||
*/
|
||||
pub fn spawn_service_recv<T:Send,Tb:Send>(
|
||||
init: extern fn() -> (SendPacketBuffered<T, Tb>,
|
||||
RecvPacketBuffered<T, Tb>),
|
||||
service: ~fn(v: SendPacketBuffered<T, Tb>))
|
||||
-> RecvPacketBuffered<T, Tb> {
|
||||
let (server, client) = init();
|
||||
|
||||
// This is some nasty gymnastics required to safely move the pipe
|
||||
// into a new task.
|
||||
let server = Cell::new(server);
|
||||
do task::spawn {
|
||||
service(server.take())
|
||||
}
|
||||
|
||||
client
|
||||
}
|
||||
|
||||
fn switch<T:Send,Tb:Send,U>(endp: std::pipes::RecvPacketBuffered<T, Tb>,
|
||||
f: &fn(v: Option<T>) -> U)
|
||||
-> U {
|
||||
f(std::pipes::try_recv(endp))
|
||||
}
|
||||
|
||||
// Here's the benchmark
|
||||
|
||||
fn bounded(count: uint) {
|
||||
use pingpong::*;
|
||||
|
||||
let mut ch = do spawn_service(init) |ch| {
|
||||
let mut count = count;
|
||||
let mut ch = ch;
|
||||
while count > 0 {
|
||||
ch = switch(ch, follow! (
|
||||
ping -> next { server::pong(next) }
|
||||
));
|
||||
|
||||
count -= 1;
|
||||
}
|
||||
};
|
||||
|
||||
let mut count = count;
|
||||
while count > 0 {
|
||||
let ch_ = client::ping(ch);
|
||||
|
||||
ch = switch(ch_, follow! (
|
||||
pong -> next { next }
|
||||
));
|
||||
|
||||
count -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn unbounded(count: uint) {
|
||||
use pingpong_unbounded::*;
|
||||
|
||||
let mut ch = do spawn_service(init) |ch| {
|
||||
let mut count = count;
|
||||
let mut ch = ch;
|
||||
while count > 0 {
|
||||
ch = switch(ch, follow! (
|
||||
ping -> next { server::pong(next) }
|
||||
));
|
||||
|
||||
count -= 1;
|
||||
}
|
||||
};
|
||||
|
||||
let mut count = count;
|
||||
while count > 0 {
|
||||
let ch_ = client::ping(ch);
|
||||
|
||||
ch = switch(ch_, follow! (
|
||||
pong -> next { next }
|
||||
));
|
||||
|
||||
count -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn timeit(f: &fn()) -> float {
|
||||
let start = precise_time_s();
|
||||
f();
|
||||
let stop = precise_time_s();
|
||||
stop - start
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let count = if os::getenv("RUST_BENCH").is_some() {
|
||||
250000
|
||||
} else {
|
||||
100
|
||||
};
|
||||
let bounded = do timeit { bounded(count) };
|
||||
let unbounded = do timeit { unbounded(count) };
|
||||
|
||||
printfln!("count: %?\n", count);
|
||||
printfln!("bounded: %? s\t(%? μs/message)",
|
||||
bounded, bounded * 1000000. / (count as float));
|
||||
printfln!("unbounded: %? s\t(%? μs/message)",
|
||||
unbounded, unbounded * 1000000. / (count as float));
|
||||
|
||||
printfln!("\n\
|
||||
bounded is %?%% faster",
|
||||
(unbounded - bounded) / bounded * 100.);
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test case for issue #2843.
|
||||
//
|
||||
|
||||
proto! streamp (
|
||||
open:send<T:Send> {
|
||||
data(T) -> open<T>
|
||||
}
|
||||
)
|
||||
|
||||
fn rendezvous() {
|
||||
let (s, c) = streamp::init();
|
||||
let streams: ~[streamp::client::open<int>] = ~[c];
|
||||
|
||||
error!("%?", streams[0]);
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
//os::getenv("FOO");
|
||||
rendezvous();
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
proto! stream (
|
||||
Stream:send<T:Send> {
|
||||
send(T) -> Stream<T>
|
||||
}
|
||||
)
|
||||
|
||||
pub fn main() {
|
||||
let (_bp, bc) = stream::init();
|
||||
|
||||
stream::client::send(bc, ~"abc");
|
||||
}
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
// xfail-fast
|
||||
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
// An example of the bank protocol from eholk's blog post.
|
||||
//
|
||||
// http://theincredibleholk.wordpress.com/2012/07/06/rusty-pipes/
|
||||
|
||||
use std::pipes;
|
||||
use std::pipes::try_recv;
|
||||
use std::ptr;
|
||||
|
||||
pub type username = ~str;
|
||||
pub type password = ~str;
|
||||
pub type money = float;
|
||||
pub type amount = float;
|
||||
|
||||
proto! bank (
|
||||
login:send {
|
||||
login(::username, ::password) -> login_response
|
||||
}
|
||||
|
||||
login_response:recv {
|
||||
ok -> connected,
|
||||
invalid -> login
|
||||
}
|
||||
|
||||
connected:send {
|
||||
deposit(::money) -> connected,
|
||||
withdrawal(::amount) -> withdrawal_response
|
||||
}
|
||||
|
||||
withdrawal_response:recv {
|
||||
money(::money) -> connected,
|
||||
insufficient_funds -> connected
|
||||
}
|
||||
)
|
||||
|
||||
fn switch<T:Send,U>(endp: pipes::RecvPacket<T>,
|
||||
f: &fn(v: Option<T>) -> U) -> U {
|
||||
f(pipes::try_recv(endp))
|
||||
}
|
||||
|
||||
macro_rules! follow (
|
||||
{
|
||||
$($message:path$(($($x: ident),+))||* -> $next:ident $e:expr)+
|
||||
} => (
|
||||
|m| match m {
|
||||
$(Some($message($($($x,)+)* next)) => {
|
||||
let $next = next;
|
||||
$e })+
|
||||
_ => { fail!() }
|
||||
}
|
||||
);
|
||||
)
|
||||
|
||||
fn client_follow(bank: bank::client::login) {
|
||||
use bank::*;
|
||||
|
||||
let bank = client::login(bank, ~"theincredibleholk", ~"1234");
|
||||
let bank = switch(bank, follow! (
|
||||
ok -> connected { connected }
|
||||
invalid -> _next { fail!("bank closed the connected") }
|
||||
));
|
||||
|
||||
let bank = client::deposit(bank, 100.00);
|
||||
let bank = client::withdrawal(bank, 50.00);
|
||||
switch(bank, follow! (
|
||||
money(m) -> _next {
|
||||
println(~"Yay! I got money!");
|
||||
}
|
||||
insufficient_funds -> _next {
|
||||
fail!("someone stole my money")
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
fn bank_client(bank: bank::client::login) {
|
||||
use bank::*;
|
||||
|
||||
let bank = client::login(bank, ~"theincredibleholk", ~"1234");
|
||||
let bank = match try_recv(bank) {
|
||||
Some(ok(connected)) => {
|
||||
connected
|
||||
}
|
||||
Some(invalid(_)) => { fail!("login unsuccessful") }
|
||||
None => { fail!("bank closed the connection") }
|
||||
};
|
||||
|
||||
let bank = client::deposit(bank, 100.00);
|
||||
let bank = client::withdrawal(bank, 50.00);
|
||||
match try_recv(bank) {
|
||||
Some(money(*)) => {
|
||||
println(~"Yay! I got money!");
|
||||
}
|
||||
Some(insufficient_funds(_)) => {
|
||||
fail!("someone stole my money")
|
||||
}
|
||||
None => {
|
||||
fail!("bank closed the connection")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
// xfail-fast
|
||||
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Make sure that we can detect when one end of the pipe is closed.
|
||||
|
||||
// xfail-win32
|
||||
// xfail-test needs sleep
|
||||
|
||||
extern mod extra;
|
||||
use extra::timer::sleep;
|
||||
use extra::uv;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::pipes::{try_recv, recv};
|
||||
use std::task;
|
||||
|
||||
proto! oneshot (
|
||||
waiting:send {
|
||||
signal -> !
|
||||
}
|
||||
)
|
||||
|
||||
pub fn main() {
|
||||
let iotask = &uv::global_loop::get();
|
||||
|
||||
let (port, chan) = oneshot::init();
|
||||
let port = Cell::new(port);
|
||||
do spawn {
|
||||
match try_recv(port.take()) {
|
||||
Some(*) => { fail!() }
|
||||
None => { }
|
||||
}
|
||||
}
|
||||
|
||||
sleep(iotask, 100);
|
||||
|
||||
task::spawn_unlinked(failtest);
|
||||
}
|
||||
|
||||
// Make sure the right thing happens during failure.
|
||||
fn failtest() {
|
||||
let (p, c) = oneshot::init();
|
||||
|
||||
do task::spawn_with(c) |_c| {
|
||||
fail!();
|
||||
}
|
||||
|
||||
error!("%?", recv(p));
|
||||
// make sure we get killed if we missed it in the receive.
|
||||
loop { task::yield() }
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
// xfail-fast
|
||||
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::pipes;
|
||||
|
||||
proto! oneshot (
|
||||
waiting:send {
|
||||
signal -> !
|
||||
}
|
||||
)
|
||||
|
||||
pub fn main() {
|
||||
let (p, c) = oneshot::init();
|
||||
let mut p = p;
|
||||
let mut c = c;
|
||||
|
||||
assert!(!pipes::peek(&mut p));
|
||||
|
||||
oneshot::client::signal(c);
|
||||
|
||||
assert!(pipes::peek(&mut p));
|
||||
}
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
// xfail-fast
|
||||
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Ping-pong is a bounded protocol. This is place where I can
|
||||
// experiment with what code the compiler should generate for bounded
|
||||
// protocols.
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::task;
|
||||
|
||||
// This was generated initially by the pipe compiler, but it's been
|
||||
// modified in hopefully straightforward ways.
|
||||
|
||||
mod pingpong {
|
||||
use std::pipes;
|
||||
use std::pipes::*;
|
||||
use std::ptr;
|
||||
|
||||
pub struct Packets {
|
||||
ping: Packet<ping>,
|
||||
pong: Packet<pong>,
|
||||
}
|
||||
|
||||
pub fn init() -> (server::ping, client::ping) {
|
||||
let buffer = ~Buffer {
|
||||
header: BufferHeader(),
|
||||
data: Packets {
|
||||
ping: mk_packet::<ping>(),
|
||||
pong: mk_packet::<pong>()
|
||||
}
|
||||
};
|
||||
do pipes::entangle_buffer(buffer) |buffer, data| {
|
||||
data.ping.set_buffer(buffer);
|
||||
data.pong.set_buffer(buffer);
|
||||
ptr::to_mut_unsafe_ptr(&mut (data.ping))
|
||||
}
|
||||
}
|
||||
pub struct ping(server::pong);
|
||||
pub struct pong(client::ping);
|
||||
pub mod client {
|
||||
use std::pipes;
|
||||
use std::pipes::*;
|
||||
use std::ptr;
|
||||
|
||||
pub fn ping(mut pipe: ping) -> pong {
|
||||
{
|
||||
let mut b = pipe.reuse_buffer();
|
||||
let s = SendPacketBuffered(&mut b.buffer.data.pong);
|
||||
let c = RecvPacketBuffered(&mut b.buffer.data.pong);
|
||||
let message = ::pingpong::ping(s);
|
||||
send(pipe, message);
|
||||
c
|
||||
}
|
||||
}
|
||||
pub type ping = pipes::SendPacketBuffered<::pingpong::ping,
|
||||
::pingpong::Packets>;
|
||||
pub type pong = pipes::RecvPacketBuffered<::pingpong::pong,
|
||||
::pingpong::Packets>;
|
||||
}
|
||||
pub mod server {
|
||||
use std::pipes;
|
||||
use std::pipes::*;
|
||||
use std::ptr;
|
||||
|
||||
pub type ping = pipes::RecvPacketBuffered<::pingpong::ping,
|
||||
::pingpong::Packets>;
|
||||
pub fn pong(mut pipe: pong) -> ping {
|
||||
{
|
||||
let mut b = pipe.reuse_buffer();
|
||||
let s = SendPacketBuffered(&mut b.buffer.data.ping);
|
||||
let c = RecvPacketBuffered(&mut b.buffer.data.ping);
|
||||
let message = ::pingpong::pong(s);
|
||||
send(pipe, message);
|
||||
c
|
||||
}
|
||||
}
|
||||
pub type pong = pipes::SendPacketBuffered<::pingpong::pong,
|
||||
::pingpong::Packets>;
|
||||
}
|
||||
}
|
||||
|
||||
mod test {
|
||||
use std::pipes::recv;
|
||||
use pingpong::{ping, pong};
|
||||
|
||||
pub fn client(chan: ::pingpong::client::ping) {
|
||||
use pingpong::client;
|
||||
|
||||
let chan = client::ping(chan); return;
|
||||
error!("Sent ping");
|
||||
let pong(_chan) = recv(chan);
|
||||
error!("Received pong");
|
||||
}
|
||||
|
||||
pub fn server(chan: ::pingpong::server::ping) {
|
||||
use pingpong::server;
|
||||
|
||||
let ping(chan) = recv(chan); return;
|
||||
error!("Received ping");
|
||||
let _chan = server::pong(chan);
|
||||
error!("Sent pong");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let (server_, client_) = ::pingpong::init();
|
||||
let client_ = Cell::new(client_);
|
||||
let server_ = Cell::new(server_);
|
||||
do task::spawn {
|
||||
let client__ = client_.take();
|
||||
test::client(client__);
|
||||
};
|
||||
do task::spawn {
|
||||
let server__ = server_.take();
|
||||
test::server(server__);
|
||||
};
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
// xfail-fast
|
||||
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// An example to make sure the protocol parsing syntax extension works.
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::option;
|
||||
use std::task;
|
||||
|
||||
proto! pingpong (
|
||||
ping:send {
|
||||
ping -> pong
|
||||
}
|
||||
|
||||
pong:recv {
|
||||
pong -> ping
|
||||
}
|
||||
)
|
||||
|
||||
mod test {
|
||||
use std::pipes::recv;
|
||||
use pingpong::{ping, pong};
|
||||
|
||||
pub fn client(chan: ::pingpong::client::ping) {
|
||||
use pingpong::client;
|
||||
|
||||
let chan = client::ping(chan);
|
||||
error!(~"Sent ping");
|
||||
let pong(_chan) = recv(chan);
|
||||
error!(~"Received pong");
|
||||
}
|
||||
|
||||
pub fn server(chan: ::pingpong::server::ping) {
|
||||
use pingpong::server;
|
||||
|
||||
let ping(chan) = recv(chan);
|
||||
error!(~"Received ping");
|
||||
let _chan = server::pong(chan);
|
||||
error!(~"Sent pong");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let (server_, client_) = pingpong::init();
|
||||
let client_ = Cell::new(client_);
|
||||
let server_ = Cell::new(server_);
|
||||
|
||||
do task::spawn {
|
||||
let client__ = client_.take();
|
||||
test::client(client__);
|
||||
};
|
||||
do task::spawn {
|
||||
let server__ = server_.take();
|
||||
test::server(server__);
|
||||
};
|
||||
}
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
// xfail-fast
|
||||
// xfail-test
|
||||
|
||||
// XFAIL'd because this is going to be revamped, and it's not compatible as
|
||||
// written with the new mutability rules.
|
||||
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Examples from Eric's internship final presentation.
|
||||
//
|
||||
// Code is easier to write in emacs, and it's good to be sure all the
|
||||
// code samples compile (or not) as they should.
|
||||
|
||||
use double_buffer::client::*;
|
||||
use double_buffer::give_buffer;
|
||||
use std::comm::Selectable;
|
||||
|
||||
macro_rules! select_if (
|
||||
{
|
||||
$index:expr,
|
||||
$count:expr,
|
||||
$port:path => [
|
||||
$($message:path$(($($x: ident),+))dont_type_this*
|
||||
-> $next:ident $e:expr),+
|
||||
],
|
||||
$( $ports:path => [
|
||||
$($messages:path$(($($xs: ident),+))dont_type_this*
|
||||
-> $nexts:ident $es:expr),+
|
||||
], )*
|
||||
} => {
|
||||
if $index == $count {
|
||||
match std::pipes::try_recv($port) {
|
||||
$(Some($message($($($x,)+)* next)) => {
|
||||
let $next = next;
|
||||
$e
|
||||
})+
|
||||
_ => fail!()
|
||||
}
|
||||
} else {
|
||||
select_if!(
|
||||
$index,
|
||||
$count + 1,
|
||||
$( $ports => [
|
||||
$($messages$(($($xs),+))dont_type_this*
|
||||
-> $nexts $es),+
|
||||
], )*
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
$index:expr,
|
||||
$count:expr,
|
||||
} => {
|
||||
fail!()
|
||||
}
|
||||
)
|
||||
|
||||
macro_rules! select (
|
||||
{
|
||||
$( $port:path => {
|
||||
$($message:path$(($($x: ident),+))dont_type_this*
|
||||
-> $next:ident $e:expr),+
|
||||
} )+
|
||||
} => ({
|
||||
let index = std::comm::selecti([$(($port).header()),+]);
|
||||
select_if!(index, 0, $( $port => [
|
||||
$($message$(($($x),+))dont_type_this* -> $next $e),+
|
||||
], )+)
|
||||
})
|
||||
)
|
||||
|
||||
// Types and protocols
|
||||
pub struct Buffer {
|
||||
foo: (),
|
||||
|
||||
}
|
||||
|
||||
impl Drop for Buffer {
|
||||
fn drop(&self) {}
|
||||
}
|
||||
|
||||
proto! double_buffer (
|
||||
acquire:send {
|
||||
request -> wait_buffer
|
||||
}
|
||||
|
||||
wait_buffer:recv {
|
||||
give_buffer(::Buffer) -> release
|
||||
}
|
||||
|
||||
release:send {
|
||||
release(::Buffer) -> acquire
|
||||
}
|
||||
)
|
||||
|
||||
// Code examples
|
||||
fn render(_buffer: &Buffer) {
|
||||
// A dummy function.
|
||||
}
|
||||
|
||||
fn draw_frame(+channel: double_buffer::client::acquire) {
|
||||
let channel = request(channel);
|
||||
select! (
|
||||
channel => {
|
||||
give_buffer(buffer) -> channel {
|
||||
render(&buffer);
|
||||
release(channel, buffer)
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_two_frames(+channel: double_buffer::client::acquire) {
|
||||
let channel = request(channel);
|
||||
let channel = select! (
|
||||
channel => {
|
||||
give_buffer(buffer) -> channel {
|
||||
render(&buffer);
|
||||
release(channel, buffer)
|
||||
}
|
||||
}
|
||||
);
|
||||
let channel = request(channel);
|
||||
select! (
|
||||
channel => {
|
||||
give_buffer(buffer) -> channel {
|
||||
render(&buffer);
|
||||
release(channel, buffer)
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(bad1)]
|
||||
fn draw_two_frames_bad1(+channel: double_buffer::client::acquire) {
|
||||
let channel = request(channel);
|
||||
select! (
|
||||
channel => {
|
||||
give_buffer(buffer) -> channel {
|
||||
render(&buffer);
|
||||
}
|
||||
}
|
||||
);
|
||||
let channel = request(channel);
|
||||
select! (
|
||||
channel => {
|
||||
give_buffer(buffer) -> channel {
|
||||
render(&buffer);
|
||||
release(channel, buffer)
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(bad2)]
|
||||
fn draw_two_frames_bad2(+channel: double_buffer::client::acquire) {
|
||||
let channel = request(channel);
|
||||
select! (
|
||||
channel => {
|
||||
give_buffer(buffer) -> channel {
|
||||
render(&buffer);
|
||||
release(channel, buffer);
|
||||
render(&buffer);
|
||||
release(channel, buffer);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
pub fn main() { }
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// FIXME #7303: xfail-test
|
||||
|
||||
// Protocols
|
||||
proto! foo (
|
||||
foo:recv {
|
||||
do_foo -> foo
|
||||
}
|
||||
)
|
||||
|
||||
proto! bar (
|
||||
bar:recv {
|
||||
do_bar(int) -> barbar,
|
||||
do_baz(bool) -> bazbar,
|
||||
}
|
||||
|
||||
barbar:send {
|
||||
rebarbar -> bar,
|
||||
}
|
||||
|
||||
bazbar:send {
|
||||
rebazbar -> bar
|
||||
}
|
||||
)
|
||||
|
||||
fn macros() {
|
||||
include!("select-macro.rs");
|
||||
}
|
||||
|
||||
// Code
|
||||
fn test(+foo: foo::client::foo, +bar: bar::client::bar) {
|
||||
use bar::do_baz;
|
||||
|
||||
select! (
|
||||
foo => {
|
||||
foo::do_foo -> _next {
|
||||
}
|
||||
}
|
||||
|
||||
bar => {
|
||||
bar::do_bar(x) -> _next {
|
||||
info!("%?", x)
|
||||
},
|
||||
|
||||
do_baz(b) -> _next {
|
||||
if b { info!("true") } else { info!("false") }
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
}
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
// xfail-fast
|
||||
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// xfail-pretty
|
||||
// xfail-win32
|
||||
// xfail-test needs sleep
|
||||
|
||||
extern mod extra;
|
||||
use extra::timer::sleep;
|
||||
use extra::uv;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::pipes::*;
|
||||
use std::pipes;
|
||||
use std::task;
|
||||
|
||||
proto! oneshot (
|
||||
waiting:send {
|
||||
signal -> !
|
||||
}
|
||||
)
|
||||
|
||||
proto! stream (
|
||||
Stream:send<T:Send> {
|
||||
send(T) -> Stream<T>
|
||||
}
|
||||
)
|
||||
|
||||
pub fn spawn_service<T:Send,Tb:Send>(
|
||||
init: extern fn() -> (RecvPacketBuffered<T, Tb>,
|
||||
SendPacketBuffered<T, Tb>),
|
||||
service: ~fn(v: RecvPacketBuffered<T, Tb>))
|
||||
-> SendPacketBuffered<T, Tb> {
|
||||
let (server, client) = init();
|
||||
|
||||
// This is some nasty gymnastics required to safely move the pipe
|
||||
// into a new task.
|
||||
let server = Cell::new(server);
|
||||
do task::spawn {
|
||||
service(server.take());
|
||||
}
|
||||
|
||||
client
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
use oneshot::client::*;
|
||||
use stream::client::*;
|
||||
|
||||
let iotask = &uv::global_loop::get();
|
||||
|
||||
let c = spawn_service(stream::init, |p| {
|
||||
error!("waiting for pipes");
|
||||
let stream::send(x, p) = recv(p);
|
||||
error!("got pipes");
|
||||
let (left, right) : (oneshot::server::waiting,
|
||||
oneshot::server::waiting)
|
||||
= x;
|
||||
error!("selecting");
|
||||
let (i, _, _) = select(~[left, right]);
|
||||
error!("selected");
|
||||
assert_eq!(i, 0);
|
||||
|
||||
error!("waiting for pipes");
|
||||
let stream::send(x, _) = recv(p);
|
||||
error!("got pipes");
|
||||
let (left, right) : (oneshot::server::waiting,
|
||||
oneshot::server::waiting)
|
||||
= x;
|
||||
error!("selecting");
|
||||
let (i, m, _) = select(~[left, right]);
|
||||
error!("selected %?", i);
|
||||
if m.is_some() {
|
||||
assert_eq!(i, 1);
|
||||
}
|
||||
});
|
||||
|
||||
let (p1, c1) = oneshot::init();
|
||||
let (p2, _c2) = oneshot::init();
|
||||
|
||||
let c = send(c, (p1, p2));
|
||||
|
||||
sleep(iotask, 100);
|
||||
|
||||
signal(c1);
|
||||
|
||||
let (p1, _c1) = oneshot::init();
|
||||
let (p2, c2) = oneshot::init();
|
||||
|
||||
send(c, (p1, p2));
|
||||
|
||||
sleep(iotask, 100);
|
||||
|
||||
signal(c2);
|
||||
|
||||
test_select2();
|
||||
}
|
||||
|
||||
fn test_select2() {
|
||||
let (ap, ac) = stream::init();
|
||||
let (bp, bc) = stream::init();
|
||||
|
||||
stream::client::send(ac, 42);
|
||||
|
||||
match pipes::select2(ap, bp) {
|
||||
Left(*) => { }
|
||||
Right(*) => { fail!() }
|
||||
}
|
||||
|
||||
stream::client::send(bc, ~"abc");
|
||||
|
||||
error!("done with first select2");
|
||||
|
||||
let (ap, ac) = stream::init();
|
||||
let (bp, bc) = stream::init();
|
||||
|
||||
stream::client::send(bc, ~"abc");
|
||||
|
||||
match pipes::select2(ap, bp) {
|
||||
Left(*) => { fail!() }
|
||||
Right(*) => { }
|
||||
}
|
||||
|
||||
stream::client::send(ac, 42);
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
// xfail-fast
|
||||
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// xfail-test needs sleep
|
||||
// xfail-win32 #7999
|
||||
|
||||
extern mod extra;
|
||||
|
||||
use extra::timer::sleep;
|
||||
use extra::uv;
|
||||
use std::cell::Cell;
|
||||
use std::pipes::*;
|
||||
use std::pipes;
|
||||
use std::task;
|
||||
|
||||
proto! oneshot (
|
||||
waiting:send {
|
||||
signal -> !
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
/** Spawn a task to provide a service.
|
||||
|
||||
It takes an initialization function that produces a send and receive
|
||||
endpoint. The send endpoint is returned to the caller and the receive
|
||||
endpoint is passed to the new task.
|
||||
|
||||
*/
|
||||
pub fn spawn_service<T:Send,Tb:Send>(
|
||||
init: extern fn() -> (RecvPacketBuffered<T, Tb>,
|
||||
SendPacketBuffered<T, Tb>),
|
||||
service: ~fn(v: RecvPacketBuffered<T, Tb>))
|
||||
-> SendPacketBuffered<T, Tb> {
|
||||
let (server, client) = init();
|
||||
|
||||
// This is some nasty gymnastics required to safely move the pipe
|
||||
// into a new task.
|
||||
let server = Cell::new(server);
|
||||
do task::spawn {
|
||||
service(server.take());
|
||||
}
|
||||
|
||||
client
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
use oneshot::client::*;
|
||||
|
||||
let c = spawn_service(oneshot::init, |p| { recv(p); });
|
||||
|
||||
let iotask = &uv::global_loop::get();
|
||||
sleep(iotask, 500);
|
||||
|
||||
signal(c);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue