Skip to content

Commit 13a4b59

Browse files
committed
core: Add send/recv/peek methods for both ports and chans
Calling peek or recv on channels can fail when the associated port is dead or unowned.
1 parent 18f8983 commit 13a4b59

File tree

1 file changed

+82
-31
lines changed

1 file changed

+82
-31
lines changed

src/libcore/comm.rs

Lines changed: 82 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export recv;
3333
export peek;
3434
export recv_chan;
3535
export select2;
36+
export methods;
3637

3738

3839
#[doc = "
@@ -67,37 +68,22 @@ fn port<T: send>() -> port<T> {
6768
port_t(@port_ptr(rustrt::new_port(sys::size_of::<T>())))
6869
}
6970

70-
#[doc = "
71-
Constructs a channel. The channel is bound to the port used to
72-
construct it.
73-
"]
74-
fn chan<T: send>(p: port<T>) -> chan<T> {
75-
chan_t(rustrt::get_port_id(***p))
76-
}
71+
impl methods<T: send> for port<T> {
72+
73+
fn chan() -> chan<T> { chan(self) }
74+
fn send(+v: T) { self.chan().send(v) }
75+
fn recv() -> T { recv(self) }
76+
fn peek() -> bool { peek(self) }
7777

78-
#[doc = "
79-
Sends data over a channel. The sent data is moved into the channel,
80-
whereupon the caller loses access to it.
81-
"]
82-
fn send<T: send>(ch: chan<T>, -data: T) {
83-
let chan_t(p) = ch;
84-
let res = rustrt::rust_port_id_send(p, data);
85-
if res != 0u unsafe {
86-
// Data sent successfully
87-
unsafe::forget(data);
88-
}
89-
task::yield();
9078
}
9179

92-
#[doc = "
93-
Receive from a port. If no data is available on the port then the
94-
task will block until data becomes available.
95-
"]
96-
fn recv<T: send>(p: port<T>) -> T { recv_(***p) }
80+
impl methods<T: send> for chan<T> {
81+
82+
fn chan() -> chan<T> { self }
83+
fn send(+v: T) { send(self, v) }
84+
fn recv() -> T { recv_chan(self) }
85+
fn peek() -> bool { peek_chan(self) }
9786

98-
#[doc = "Returns true if there are messages available"]
99-
fn peek<T: send>(p: port<T>) -> bool {
100-
rustrt::rust_port_size(***p) != 0u as libc::size_t
10187
}
10288

10389
resource port_ptr<T: send>(po: *rust_port) {
@@ -121,9 +107,15 @@ resource port_ptr<T: send>(po: *rust_port) {
121107
rustrt::del_port(po);
122108
}
123109

110+
#[doc = "
111+
Internal function for converting from a channel to a port
124112
125-
#[doc(hidden)]
126-
fn recv_chan<T: send>(ch: comm::chan<T>) -> T {
113+
# Failure
114+
115+
Fails if the port is detached or dead. Fails if the port
116+
is owned by a different task.
117+
"]
118+
fn as_raw_port<T: send, U>(ch: comm::chan<T>, f: fn(*rust_port) -> U) -> U {
127119
resource portref(p: *rust_port) {
128120
if !ptr::is_null(p) {
129121
rustrt::rust_port_drop(p);
@@ -135,10 +127,50 @@ fn recv_chan<T: send>(ch: comm::chan<T>) -> T {
135127
if ptr::is_null(*p) {
136128
fail "unable to locate port for channel"
137129
} else if rustrt::get_task_id() != rustrt::rust_port_task(*p) {
138-
fail "attempting to receive on unowned channel"
130+
fail "unable to access unowned port"
139131
}
140132

141-
recv_(*p)
133+
f(*p)
134+
}
135+
136+
#[doc = "
137+
Constructs a channel. The channel is bound to the port used to
138+
construct it.
139+
"]
140+
fn chan<T: send>(p: port<T>) -> chan<T> {
141+
chan_t(rustrt::get_port_id(***p))
142+
}
143+
144+
#[doc = "
145+
Sends data over a channel. The sent data is moved into the channel,
146+
whereupon the caller loses access to it.
147+
"]
148+
fn send<T: send>(ch: chan<T>, -data: T) {
149+
let chan_t(p) = ch;
150+
let res = rustrt::rust_port_id_send(p, data);
151+
if res != 0u unsafe {
152+
// Data sent successfully
153+
unsafe::forget(data);
154+
}
155+
task::yield();
156+
}
157+
158+
#[doc = "
159+
Receive from a port. If no data is available on the port then the
160+
task will block until data becomes available.
161+
"]
162+
fn recv<T: send>(p: port<T>) -> T { recv_(***p) }
163+
164+
#[doc = "Returns true if there are messages available"]
165+
fn peek<T: send>(p: port<T>) -> bool { peek_(***p) }
166+
167+
#[doc(hidden)]
168+
fn recv_chan<T: send>(ch: comm::chan<T>) -> T {
169+
as_raw_port(ch, recv_(_))
170+
}
171+
172+
fn peek_chan<T: send>(ch: comm::chan<T>) -> bool {
173+
as_raw_port(ch, peek_(_))
142174
}
143175

144176
#[doc = "Receive on a raw port pointer"]
@@ -160,6 +192,10 @@ fn recv_<T: send>(p: *rust_port) -> T {
160192
ret res;
161193
}
162194

195+
fn peek_(p: *rust_port) -> bool unsafe {
196+
rustrt::rust_port_size(p) != 0u as libc::size_t
197+
}
198+
163199
#[doc = "Receive on one of two ports"]
164200
fn select2<A: send, B: send>(p_a: port<A>, p_b: port<B>)
165201
-> either<A, B> unsafe {
@@ -391,3 +427,18 @@ fn test_recv_chan_wrong_task() {
391427
recv_chan(ch)
392428
})
393429
}
430+
431+
#[test]
432+
fn test_port_send() {
433+
let po = port();
434+
po.send(());
435+
po.recv();
436+
}
437+
438+
#[test]
439+
fn test_chan_peek() {
440+
let po = port();
441+
let ch = po.chan();
442+
ch.send(());
443+
assert ch.peek();
444+
}

0 commit comments

Comments
 (0)