]> git.lizzy.rs Git - rust.git/blob - src/test/run-pass/issue-2718.rs
5eb9453134dea74705ea791c013ebe818377ffeb
[rust.git] / src / test / run-pass / issue-2718.rs
1
2 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
3 // file at the top-level directory of this distribution and at
4 // http://rust-lang.org/COPYRIGHT.
5 //
6 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
7 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
8 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
9 // option. This file may not be copied, modified, or distributed
10 // except according to those terms.
11
12 #![feature(unsafe_destructor)]
13
14 pub type Task = int;
15
16 // tjc: I don't know why
17 pub mod pipes {
18     use super::Task;
19     use std::mem::{forget, transmute};
20     use std::mem::{replace, swap};
21     use std::mem;
22     use std::task;
23
24     pub struct Stuff<T> {
25         state: state,
26         blocked_task: Option<Task>,
27         payload: Option<T>
28     }
29
30     #[deriving(PartialEq, Show)]
31     #[repr(int)]
32     pub enum state {
33         empty,
34         full,
35         blocked,
36         terminated
37     }
38
39     pub struct packet<T> {
40         state: state,
41         blocked_task: Option<Task>,
42         payload: Option<T>
43     }
44
45     pub fn packet<T:Send>() -> *packet<T> {
46         unsafe {
47             let p: *packet<T> = mem::transmute(box Stuff{
48                 state: empty,
49                 blocked_task: None::<Task>,
50                 payload: None::<T>
51             });
52             p
53         }
54     }
55
56     mod rusti {
57       pub fn atomic_xchg(_dst: &mut int, _src: int) -> int { fail!(); }
58       pub fn atomic_xchg_acq(_dst: &mut int, _src: int) -> int { fail!(); }
59       pub fn atomic_xchg_rel(_dst: &mut int, _src: int) -> int { fail!(); }
60     }
61
62     // We should consider moving this to ::std::unsafe, although I
63     // suspect graydon would want us to use void pointers instead.
64     pub unsafe fn uniquify<T>(x: *T) -> Box<T> {
65         mem::transmute(x)
66     }
67
68     pub fn swap_state_acq(dst: &mut state, src: state) -> state {
69         unsafe {
70             transmute(rusti::atomic_xchg_acq(transmute(dst), src as int))
71         }
72     }
73
74     pub fn swap_state_rel(dst: &mut state, src: state) -> state {
75         unsafe {
76             transmute(rusti::atomic_xchg_rel(transmute(dst), src as int))
77         }
78     }
79
80     pub fn send<T:Send>(mut p: send_packet<T>, payload: T) {
81         let p = p.unwrap();
82         let mut p = unsafe { uniquify(p) };
83         assert!((*p).payload.is_none());
84         (*p).payload = Some(payload);
85         let old_state = swap_state_rel(&mut (*p).state, full);
86         match old_state {
87           empty => {
88             // Yay, fastpath.
89
90             // The receiver will eventually clean this up.
91             unsafe { forget(p); }
92           }
93           full => { fail!("duplicate send") }
94           blocked => {
95
96             // The receiver will eventually clean this up.
97             unsafe { forget(p); }
98           }
99           terminated => {
100             // The receiver will never receive this. Rely on drop_glue
101             // to clean everything up.
102           }
103         }
104     }
105
106     pub fn recv<T:Send>(mut p: recv_packet<T>) -> Option<T> {
107         let p = p.unwrap();
108         let mut p = unsafe { uniquify(p) };
109         loop {
110             let old_state = swap_state_acq(&mut (*p).state,
111                                            blocked);
112             match old_state {
113               empty | blocked => { task::deschedule(); }
114               full => {
115                 let payload = replace(&mut p.payload, None);
116                 return Some(payload.unwrap())
117               }
118               terminated => {
119                 assert_eq!(old_state, terminated);
120                 return None;
121               }
122             }
123         }
124     }
125
126     pub fn sender_terminate<T:Send>(p: *packet<T>) {
127         let mut p = unsafe { uniquify(p) };
128         match swap_state_rel(&mut (*p).state, terminated) {
129           empty | blocked => {
130             // The receiver will eventually clean up.
131             unsafe { forget(p) }
132           }
133           full => {
134             // This is impossible
135             fail!("you dun goofed")
136           }
137           terminated => {
138             // I have to clean up, use drop_glue
139           }
140         }
141     }
142
143     pub fn receiver_terminate<T:Send>(p: *packet<T>) {
144         let mut p = unsafe { uniquify(p) };
145         match swap_state_rel(&mut (*p).state, terminated) {
146           empty => {
147             // the sender will clean up
148             unsafe { forget(p) }
149           }
150           blocked => {
151             // this shouldn't happen.
152             fail!("terminating a blocked packet")
153           }
154           terminated | full => {
155             // I have to clean up, use drop_glue
156           }
157         }
158     }
159
160     pub struct send_packet<T> {
161         p: Option<*packet<T>>,
162     }
163
164     #[unsafe_destructor]
165     impl<T:Send> Drop for send_packet<T> {
166         fn drop(&mut self) {
167             unsafe {
168                 if self.p != None {
169                     let self_p: &mut Option<*packet<T>> =
170                         mem::transmute(&self.p);
171                     let p = replace(self_p, None);
172                     sender_terminate(p.unwrap())
173                 }
174             }
175         }
176     }
177
178     impl<T:Send> send_packet<T> {
179         pub fn unwrap(&mut self) -> *packet<T> {
180             replace(&mut self.p, None).unwrap()
181         }
182     }
183
184     pub fn send_packet<T:Send>(p: *packet<T>) -> send_packet<T> {
185         send_packet {
186             p: Some(p)
187         }
188     }
189
190     pub struct recv_packet<T> {
191         p: Option<*packet<T>>,
192     }
193
194     #[unsafe_destructor]
195     impl<T:Send> Drop for recv_packet<T> {
196         fn drop(&mut self) {
197             unsafe {
198                 if self.p != None {
199                     let self_p: &mut Option<*packet<T>> =
200                         mem::transmute(&self.p);
201                     let p = replace(self_p, None);
202                     receiver_terminate(p.unwrap())
203                 }
204             }
205         }
206     }
207
208     impl<T:Send> recv_packet<T> {
209         pub fn unwrap(&mut self) -> *packet<T> {
210             replace(&mut self.p, None).unwrap()
211         }
212     }
213
214     pub fn recv_packet<T:Send>(p: *packet<T>) -> recv_packet<T> {
215         recv_packet {
216             p: Some(p)
217         }
218     }
219
220     pub fn entangle<T:Send>() -> (send_packet<T>, recv_packet<T>) {
221         let p = packet();
222         (send_packet(p), recv_packet(p))
223     }
224 }
225
226 pub mod pingpong {
227     use std::mem;
228
229     pub struct ping(::pipes::send_packet<pong>);
230     pub struct pong(::pipes::send_packet<ping>);
231
232     pub fn liberate_ping(p: ping) -> ::pipes::send_packet<pong> {
233         unsafe {
234             let _addr : *::pipes::send_packet<pong> = match &p {
235               &ping(ref x) => { mem::transmute(x) }
236             };
237             fail!()
238         }
239     }
240
241     pub fn liberate_pong(p: pong) -> ::pipes::send_packet<ping> {
242         unsafe {
243             let _addr : *::pipes::send_packet<ping> = match &p {
244               &pong(ref x) => { mem::transmute(x) }
245             };
246             fail!()
247         }
248     }
249
250     pub fn init() -> (client::ping, server::ping) {
251         ::pipes::entangle()
252     }
253
254     pub mod client {
255         use pingpong;
256
257         pub type ping = ::pipes::send_packet<pingpong::ping>;
258         pub type pong = ::pipes::recv_packet<pingpong::pong>;
259
260         pub fn do_ping(c: ping) -> pong {
261             let (sp, rp) = ::pipes::entangle();
262
263             ::pipes::send(c, pingpong::ping(sp));
264             rp
265         }
266
267         pub fn do_pong(c: pong) -> (ping, ()) {
268             let packet = ::pipes::recv(c);
269             if packet.is_none() {
270                 fail!("sender closed the connection")
271             }
272             (pingpong::liberate_pong(packet.unwrap()), ())
273         }
274     }
275
276     pub mod server {
277         use pingpong;
278
279         pub type ping = ::pipes::recv_packet<pingpong::ping>;
280         pub type pong = ::pipes::send_packet<pingpong::pong>;
281
282         pub fn do_ping(c: ping) -> (pong, ()) {
283             let packet = ::pipes::recv(c);
284             if packet.is_none() {
285                 fail!("sender closed the connection")
286             }
287             (pingpong::liberate_ping(packet.unwrap()), ())
288         }
289
290         pub fn do_pong(c: pong) -> ping {
291             let (sp, rp) = ::pipes::entangle();
292             ::pipes::send(c, pingpong::pong(sp));
293             rp
294         }
295     }
296 }
297
298 fn client(chan: pingpong::client::ping) {
299     let chan = pingpong::client::do_ping(chan);
300     println!("Sent ping");
301     let (_chan, _data) = pingpong::client::do_pong(chan);
302     println!("Received pong");
303 }
304
305 fn server(chan: pingpong::server::ping) {
306     let (chan, _data) = pingpong::server::do_ping(chan);
307     println!("Received ping");
308     let _chan = pingpong::server::do_pong(chan);
309     println!("Sent pong");
310 }
311
312 pub fn main() {
313   /*
314 //    Commented out because of option::get error
315
316     let (client_, server_) = pingpong::init();
317
318     task::spawn {|client_|
319         let client__ = client_.take();
320         client(client__);
321     };
322     task::spawn {|server_|
323         let server__ = server_.take();
324         server(server_ˊ);
325     };
326   */
327 }