summary refs log tree commit diff
path: root/src/test/auxiliary/test_comm.rs
blob: 77f107fda090d0b0384d66a04d15084ea4ed234e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*
  Minimized version of core::comm for testing. 

  Could probably be more minimal.
 */
#[legacy_exports];

use libc::size_t;

export port::{};
export port;
export recv;


/**
 * A communication endpoint that can receive messages
 *
 * Each port has a unique per-task identity and may not be replicated or
 * transmitted. If a port value is copied, both copies refer to the same
 * port.  Ports may be associated with multiple `chan`s.
 */
enum port<T: Send> {
    port_t(@port_ptr<T>)
}

/// Constructs a port
fn port<T: Send>() -> port<T> {
    port_t(@port_ptr(rustrt::new_port(sys::size_of::<T>() as size_t)))
}

struct port_ptr<T:Send> {
   po: *rust_port,
   drop unsafe {
    debug!("in the port_ptr destructor");
       do task::unkillable {
        let yield = 0u;
        let yieldp = ptr::addr_of(&yield);
        rustrt::rust_port_begin_detach(self.po, yieldp);
        if yield != 0u {
            task::yield();
        }
        rustrt::rust_port_end_detach(self.po);

        while rustrt::rust_port_size(self.po) > 0u as size_t {
            recv_::<T>(self.po);
        }
        rustrt::del_port(self.po);
    }
  }
}

fn port_ptr<T: Send>(po: *rust_port) -> port_ptr<T> {
    debug!("in the port_ptr constructor");
    port_ptr {
        po: po
    }
}

/**
 * Receive from a port.  If no data is available on the port then the
 * task will block until data becomes available.
 */
fn recv<T: Send>(p: port<T>) -> T { recv_((**p).po) }


/// Receive on a raw port pointer
fn recv_<T: Send>(p: *rust_port) -> T {
    let yield = 0u;
    let yieldp = ptr::addr_of(&yield);
    let mut res;
    res = rusti::init::<T>();
    rustrt::port_recv(ptr::addr_of(&res) as *uint, p, yieldp);

    if yield != 0u {
        // Data isn't available yet, so res has not been initialized.
        task::yield();
    } else {
        // In the absense of compiler-generated preemption points
        // this is a good place to yield
        task::yield();
    }
    return res;
}


/* Implementation details */


enum rust_port {}

type port_id = int;

#[abi = "cdecl"]
extern mod rustrt {
    #[legacy_exports];

    fn new_port(unit_sz: libc::size_t) -> *rust_port;
    fn del_port(po: *rust_port);
    fn rust_port_begin_detach(po: *rust_port,
                              yield: *libc::uintptr_t);
    fn rust_port_end_detach(po: *rust_port);
    fn rust_port_size(po: *rust_port) -> libc::size_t;
    fn port_recv(dptr: *uint, po: *rust_port,
                 yield: *libc::uintptr_t);
}

#[abi = "rust-intrinsic"]
extern mod rusti {
    #[legacy_exports];
    fn init<T>() -> T;
}