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