]> git.lizzy.rs Git - rust.git/blob - src/test/ui/regions/issue-2718.rs
Auto merge of #93718 - thomcc:used-macho, r=pnkfelix
[rust.git] / src / test / ui / regions / issue-2718.rs
1 // run-pass
2 #![allow(dead_code)]
3 #![allow(unused_unsafe)]
4 #![allow(unused_imports)]
5 #![allow(non_camel_case_types)]
6
7 pub type Task = isize;
8
9 // tjc: I don't know why
10 pub mod pipes {
11     use self::state::{empty, full, blocked, terminated};
12     use super::Task;
13     use std::mem::{forget, transmute};
14     use std::mem::{replace, swap};
15     use std::mem;
16     use std::thread;
17     use std::marker::Send;
18
19     pub struct Stuff<T> {
20         state: state,
21         blocked_task: Option<Task>,
22         payload: Option<T>
23     }
24
25     #[derive(PartialEq, Debug)]
26     #[repr(isize)]
27     pub enum state {
28         empty,
29         full,
30         blocked,
31         terminated
32     }
33
34     pub struct packet<T> {
35         state: state,
36         blocked_task: Option<Task>,
37         payload: Option<T>
38     }
39
40     unsafe impl<T:Send> Send for packet<T> {}
41
42     pub fn packet<T:Send>() -> *const packet<T> {
43         unsafe {
44             let p: *const packet<T> = mem::transmute(Box::new(Stuff{
45                 state: empty,
46                 blocked_task: None::<Task>,
47                 payload: None::<T>
48             }));
49             p
50         }
51     }
52
53     mod rusti {
54       pub fn atomic_xchg(_dst: &mut isize, _src: isize) -> isize { panic!(); }
55       pub fn atomic_xchg_acq(_dst: &mut isize, _src: isize) -> isize { panic!(); }
56       pub fn atomic_xchg_rel(_dst: &mut isize, _src: isize) -> isize { panic!(); }
57     }
58
59     // We should consider moving this to ::std::unsafe, although I
60     // suspect graydon would want us to use void pointers instead.
61     pub unsafe fn uniquify<T>(x: *const T) -> Box<T> {
62         mem::transmute(x)
63     }
64
65     pub fn swap_state_acq(dst: &mut state, src: state) -> state {
66         unsafe {
67             transmute(rusti::atomic_xchg_acq(transmute(dst), src as isize))
68         }
69     }
70
71     pub fn swap_state_rel(dst: &mut state, src: state) -> state {
72         unsafe {
73             transmute(rusti::atomic_xchg_rel(transmute(dst), src as isize))
74         }
75     }
76
77     pub fn send<T:Send>(mut p: send_packet<T>, payload: T) {
78         let p = p.unwrap();
79         let mut p = unsafe { uniquify(p) };
80         assert!((*p).payload.is_none());
81         (*p).payload = Some(payload);
82         let old_state = swap_state_rel(&mut (*p).state, full);
83         match old_state {
84           empty => {
85             // Yay, fastpath.
86
87             // The receiver will eventually clean this up.
88             unsafe { forget(p); }
89           }
90           full => { panic!("duplicate send") }
91           blocked => {
92
93             // The receiver will eventually clean this up.
94             unsafe { forget(p); }
95           }
96           terminated => {
97             // The receiver will never receive this. Rely on drop_glue
98             // to clean everything up.
99           }
100         }
101     }
102
103     pub fn recv<T:Send>(mut p: recv_packet<T>) -> Option<T> {
104         let p = p.unwrap();
105         let mut p = unsafe { uniquify(p) };
106         loop {
107             let old_state = swap_state_acq(&mut (*p).state,
108                                            blocked);
109             match old_state {
110               empty | blocked => { thread::yield_now(); }
111               full => {
112                 let payload = replace(&mut p.payload, None);
113                 return Some(payload.unwrap())
114               }
115               terminated => {
116                 assert_eq!(old_state, terminated);
117                 return None;
118               }
119             }
120         }
121     }
122
123     pub fn sender_terminate<T:Send>(p: *const packet<T>) {
124         let mut p = unsafe { uniquify(p) };
125         match swap_state_rel(&mut (*p).state, terminated) {
126           empty | blocked => {
127             // The receiver will eventually clean up.
128             unsafe { forget(p) }
129           }
130           full => {
131             // This is impossible
132             panic!("you dun goofed")
133           }
134           terminated => {
135             // I have to clean up, use drop_glue
136           }
137         }
138     }
139
140     pub fn receiver_terminate<T:Send>(p: *const packet<T>) {
141         let mut p = unsafe { uniquify(p) };
142         match swap_state_rel(&mut (*p).state, terminated) {
143           empty => {
144             // the sender will clean up
145             unsafe { forget(p) }
146           }
147           blocked => {
148             // this shouldn't happen.
149             panic!("terminating a blocked packet")
150           }
151           terminated | full => {
152             // I have to clean up, use drop_glue
153           }
154         }
155     }
156
157     pub struct send_packet<T:Send> {
158         p: Option<*const packet<T>>,
159     }
160
161     impl<T:Send> Drop for send_packet<T> {
162         fn drop(&mut self) {
163             unsafe {
164                 if self.p != None {
165                     let self_p: &mut Option<*const packet<T>> =
166                         mem::transmute(&mut self.p);
167                     let p = replace(self_p, None);
168                     sender_terminate(p.unwrap())
169                 }
170             }
171         }
172     }
173
174     impl<T:Send> send_packet<T> {
175         pub fn unwrap(&mut self) -> *const packet<T> {
176             replace(&mut self.p, None).unwrap()
177         }
178     }
179
180     pub fn send_packet<T:Send>(p: *const packet<T>) -> send_packet<T> {
181         send_packet {
182             p: Some(p)
183         }
184     }
185
186     pub struct recv_packet<T:Send> {
187         p: Option<*const packet<T>>,
188     }
189
190     impl<T:Send> Drop for recv_packet<T> {
191         fn drop(&mut self) {
192             unsafe {
193                 if self.p != None {
194                     let self_p: &mut Option<*const packet<T>> =
195                         mem::transmute(&mut self.p);
196                     let p = replace(self_p, None);
197                     receiver_terminate(p.unwrap())
198                 }
199             }
200         }
201     }
202
203     impl<T:Send> recv_packet<T> {
204         pub fn unwrap(&mut self) -> *const packet<T> {
205             replace(&mut self.p, None).unwrap()
206         }
207     }
208
209     pub fn recv_packet<T:Send>(p: *const packet<T>) -> recv_packet<T> {
210         recv_packet {
211             p: Some(p)
212         }
213     }
214
215     pub fn entangle<T:Send>() -> (send_packet<T>, recv_packet<T>) {
216         let p = packet();
217         (send_packet(p), recv_packet(p))
218     }
219 }
220
221 pub mod pingpong {
222     use std::mem;
223
224     pub struct ping(::pipes::send_packet<pong>);
225
226     unsafe impl Send for ping {}
227
228     pub struct pong(::pipes::send_packet<ping>);
229
230     unsafe impl Send for pong {}
231
232     pub fn liberate_ping(p: ping) -> ::pipes::send_packet<pong> {
233         unsafe {
234             let _addr : *const ::pipes::send_packet<pong> = match &p {
235               &ping(ref x) => { mem::transmute(x) }
236             };
237             panic!()
238         }
239     }
240
241     pub fn liberate_pong(p: pong) -> ::pipes::send_packet<ping> {
242         unsafe {
243             let _addr : *const ::pipes::send_packet<ping> = match &p {
244               &pong(ref x) => { mem::transmute(x) }
245             };
246             panic!()
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                 panic!("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                 panic!("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 }