1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 #![allow(non_camel_case_types)]
14 pub type Task
= isize;
16 // tjc: I don't know why
18 use self::state
::{empty, full, blocked, terminated}
;
20 use std
::mem
::{forget, transmute}
;
21 use std
::mem
::{replace, swap}
;
24 use std
::marker
::Send
;
28 blocked_task
: Option
<Task
>,
32 #[derive(PartialEq, Debug)]
41 pub struct packet
<T
> {
43 blocked_task
: Option
<Task
>,
47 unsafe impl<T
:Send
> Send
for packet
<T
> {}
49 pub fn packet
<T
:Send
>() -> *const packet
<T
> {
51 let p
: *const packet
<T
> = mem
::transmute(Box
::new(Stuff
{
53 blocked_task
: None
::<Task
>,
61 pub fn atomic_xchg(_dst
: &mut isize, _src
: isize) -> isize { panic!(); }
62 pub fn atomic_xchg_acq(_dst
: &mut isize, _src
: isize) -> isize { panic!(); }
63 pub fn atomic_xchg_rel(_dst
: &mut isize, _src
: isize) -> isize { panic!(); }
66 // We should consider moving this to ::std::unsafe, although I
67 // suspect graydon would want us to use void pointers instead.
68 pub unsafe fn uniquify
<T
>(x
: *const T
) -> Box
<T
> {
72 pub fn swap_state_acq(dst
: &mut state
, src
: state
) -> state
{
74 transmute(rusti
::atomic_xchg_acq(transmute(dst
), src
as isize))
78 pub fn swap_state_rel(dst
: &mut state
, src
: state
) -> state
{
80 transmute(rusti
::atomic_xchg_rel(transmute(dst
), src
as isize))
84 pub fn send
<T
:Send
>(mut p
: send_packet
<T
>, payload
: T
) {
86 let mut p
= unsafe { uniquify(p) }
;
87 assert
!((*p
).payload
.is_none());
88 (*p
).payload
= Some(payload
);
89 let old_state
= swap_state_rel(&mut (*p
).state
, full
);
94 // The receiver will eventually clean this up.
97 full
=> { panic!("duplicate send") }
100 // The receiver will eventually clean this up.
101 unsafe { forget(p); }
104 // The receiver will never receive this. Rely on drop_glue
105 // to clean everything up.
110 pub fn recv
<T
:Send
>(mut p
: recv_packet
<T
>) -> Option
<T
> {
112 let mut p
= unsafe { uniquify(p) }
;
114 let old_state
= swap_state_acq(&mut (*p
).state
,
117 empty
| blocked
=> { thread::yield_now(); }
119 let payload
= replace(&mut p
.payload
, None
);
120 return Some(payload
.unwrap())
123 assert_eq
!(old_state
, terminated
);
130 pub fn sender_terminate
<T
:Send
>(p
: *const packet
<T
>) {
131 let mut p
= unsafe { uniquify(p) }
;
132 match swap_state_rel(&mut (*p
).state
, terminated
) {
134 // The receiver will eventually clean up.
138 // This is impossible
139 panic
!("you dun goofed")
142 // I have to clean up, use drop_glue
147 pub fn receiver_terminate
<T
:Send
>(p
: *const packet
<T
>) {
148 let mut p
= unsafe { uniquify(p) }
;
149 match swap_state_rel(&mut (*p
).state
, terminated
) {
151 // the sender will clean up
155 // this shouldn't happen.
156 panic
!("terminating a blocked packet")
158 terminated
| full
=> {
159 // I have to clean up, use drop_glue
164 pub struct send_packet
<T
:Send
> {
165 p
: Option
<*const packet
<T
>>,
168 impl<T
:Send
> Drop
for send_packet
<T
> {
172 let self_p
: &mut Option
<*const packet
<T
>> =
173 mem
::transmute(&mut self.p
);
174 let p
= replace(self_p
, None
);
175 sender_terminate(p
.unwrap())
181 impl<T
:Send
> send_packet
<T
> {
182 pub fn unwrap(&mut self) -> *const packet
<T
> {
183 replace(&mut self.p
, None
).unwrap()
187 pub fn send_packet
<T
:Send
>(p
: *const packet
<T
>) -> send_packet
<T
> {
193 pub struct recv_packet
<T
:Send
> {
194 p
: Option
<*const packet
<T
>>,
197 impl<T
:Send
> Drop
for recv_packet
<T
> {
201 let self_p
: &mut Option
<*const packet
<T
>> =
202 mem
::transmute(&mut self.p
);
203 let p
= replace(self_p
, None
);
204 receiver_terminate(p
.unwrap())
210 impl<T
:Send
> recv_packet
<T
> {
211 pub fn unwrap(&mut self) -> *const packet
<T
> {
212 replace(&mut self.p
, None
).unwrap()
216 pub fn recv_packet
<T
:Send
>(p
: *const packet
<T
>) -> recv_packet
<T
> {
222 pub fn entangle
<T
:Send
>() -> (send_packet
<T
>, recv_packet
<T
>) {
224 (send_packet(p
), recv_packet(p
))
231 pub struct ping(::pipes
::send_packet
<pong
>);
233 unsafe impl Send
for ping {}
235 pub struct pong(::pipes
::send_packet
<ping
>);
237 unsafe impl Send
for pong {}
239 pub fn liberate_ping(p
: ping
) -> ::pipes
::send_packet
<pong
> {
241 let _addr
: *const ::pipes
::send_packet
<pong
> = match &p
{
242 &ping(ref x
) => { mem::transmute(x) }
248 pub fn liberate_pong(p
: pong
) -> ::pipes
::send_packet
<ping
> {
250 let _addr
: *const ::pipes
::send_packet
<ping
> = match &p
{
251 &pong(ref x
) => { mem::transmute(x) }
257 pub fn init() -> (client
::ping
, server
::ping
) {
264 pub type ping
= ::pipes
::send_packet
<pingpong
::ping
>;
265 pub type pong
= ::pipes
::recv_packet
<pingpong
::pong
>;
267 pub fn do_ping(c
: ping
) -> pong
{
268 let (sp
, rp
) = ::pipes
::entangle();
270 ::pipes
::send(c
, pingpong
::ping(sp
));
274 pub fn do_pong(c
: pong
) -> (ping
, ()) {
275 let packet
= ::pipes
::recv(c
);
276 if packet
.is_none() {
277 panic
!("sender closed the connection")
279 (pingpong
::liberate_pong(packet
.unwrap()), ())
286 pub type ping
= ::pipes
::recv_packet
<pingpong
::ping
>;
287 pub type pong
= ::pipes
::send_packet
<pingpong
::pong
>;
289 pub fn do_ping(c
: ping
) -> (pong
, ()) {
290 let packet
= ::pipes
::recv(c
);
291 if packet
.is_none() {
292 panic
!("sender closed the connection")
294 (pingpong
::liberate_ping(packet
.unwrap()), ())
297 pub fn do_pong(c
: pong
) -> ping
{
298 let (sp
, rp
) = ::pipes
::entangle();
299 ::pipes
::send(c
, pingpong
::pong(sp
));
305 fn client(chan
: pingpong
::client
::ping
) {
306 let chan
= pingpong
::client
::do_ping(chan
);
307 println
!("Sent ping");
308 let (_chan
, _data
) = pingpong
::client
::do_pong(chan
);
309 println
!("Received pong");
312 fn server(chan
: pingpong
::server
::ping
) {
313 let (chan
, _data
) = pingpong
::server
::do_ping(chan
);
314 println
!("Received ping");
315 let _chan
= pingpong
::server
::do_pong(chan
);
316 println
!("Sent pong");
321 // Commented out because of option::get error
323 let (client_, server_) = pingpong::init();
325 task::spawn {|client_|
326 let client__ = client_.take();
329 task::spawn {|server_|
330 let server__ = server_.take();