]> git.proxmox.com Git - rustc.git/blame - src/vendor/magenta/src/port.rs
New upstream version 1.22.1+dfsg1
[rustc.git] / src / vendor / magenta / src / port.rs
CommitLineData
ea8adc8c
XL
1// Copyright 2017 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Type-safe bindings for Magenta port objects.
6
7use std::mem;
8
9use {HandleBase, Handle, HandleRef, Signals, Status, Time};
10use {sys, into_result};
11
12/// An object representing a Magenta
13/// [port](https://fuchsia.googlesource.com/magenta/+/master/docs/objects/port.md).
14///
15/// As essentially a subtype of `Handle`, it can be freely interconverted.
16#[derive(Debug, Eq, PartialEq)]
17pub struct Port(Handle);
18
19impl HandleBase for Port {
20 fn get_ref(&self) -> HandleRef {
21 self.0.get_ref()
22 }
23
24 fn from_handle(handle: Handle) -> Self {
25 Port(handle)
26 }
27}
28
29/// A packet sent through a port. This is a type-safe wrapper for
30/// [mx_port_packet_t](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/port_wait2.md).
31#[derive(PartialEq, Eq, Debug)]
32pub struct Packet(sys::mx_port_packet_t);
33
34/// The contents of a `Packet`.
35#[derive(Debug, Copy, Clone)]
36pub enum PacketContents {
37 /// A user-generated packet.
38 User(UserPacket),
39 /// A one-shot signal packet generated via `object_wait_async`.
40 SignalOne(SignalPacket),
41 /// A repeating signal packet generated via `object_wait_async`.
42 SignalRep(SignalPacket),
43}
44
45/// Contents of a user packet (one sent by `port_queue`). This is a type-safe wrapper for
46/// [mx_packet_user_t](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/port_wait2.md).
47#[derive(Debug, Copy, Clone)]
48pub struct UserPacket(sys::mx_packet_user_t);
49
50/// Contents of a signal packet (one generated by the kernel). This is a type-safe wrapper for
51/// [mx_packet_signal_t](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/port_wait2.md).
52#[derive(Debug, Copy, Clone)]
53pub struct SignalPacket(sys::mx_packet_signal_t);
54
55impl Packet {
56 /// Creates a new packet with `UserPacket` data.
57 pub fn from_user_packet(key: u64, status: i32, user: UserPacket) -> Packet {
58 Packet(
59 sys::mx_port_packet_t {
60 key: key,
61 packet_type: sys::mx_packet_type_t::MX_PKT_TYPE_USER,
62 status: status,
63 union: user.0,
64 }
65 )
66 }
67
68 /// The packet's key.
69 pub fn key(&self) -> u64 {
70 self.0.key
71 }
72
73 /// The packet's status.
74 // TODO: should this type be wrapped?
75 pub fn status(&self) -> i32 {
76 self.0.status
77 }
78
79 /// The contents of the packet.
80 pub fn contents(&self) -> PacketContents {
81 if self.0.packet_type == sys::mx_packet_type_t::MX_PKT_TYPE_USER {
82 PacketContents::User(UserPacket(self.0.union))
83 } else if self.0.packet_type == sys::mx_packet_type_t::MX_PKT_TYPE_SIGNAL_ONE {
84 PacketContents::SignalOne(SignalPacket(unsafe { mem::transmute_copy(&self.0.union) }))
85 } else if self.0.packet_type == sys::mx_packet_type_t::MX_PKT_TYPE_SIGNAL_REP {
86 PacketContents::SignalRep(SignalPacket(unsafe { mem::transmute_copy(&self.0.union) }))
87 } else {
88 panic!("unexpected packet type");
89 }
90 }
91}
92
93impl UserPacket {
94 pub fn from_u8_array(val: [u8; 32]) -> UserPacket {
95 UserPacket(val)
96 }
97
98 pub fn as_u8_array(&self) -> &[u8; 32] {
99 &self.0
100 }
101
102 pub fn as_mut_u8_array(&mut self) -> &mut [u8; 32] {
103 &mut self.0
104 }
105}
106
107impl SignalPacket {
108 /// The signals used in the call to `object_wait_async`.
109 pub fn trigger(&self) -> Signals {
110 self.0.trigger
111 }
112
113 /// The observed signals.
114 pub fn observed(&self) -> Signals {
115 self.0.observed
116 }
117
118 /// A per object count of pending operations.
119 pub fn count(&self) -> u64 {
120 self.0.count
121 }
122}
123
124impl Port {
125 /// Create an IO port, allowing IO packets to be read and enqueued.
126 ///
127 /// Wraps the
128 /// [mx_port_create](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/port_create.md)
129 /// syscall.
130 pub fn create(opts: PortOpts) -> Result<Port, Status> {
131 unsafe {
132 let mut handle = 0;
133 let status = sys::mx_port_create(opts as u32, &mut handle);
134 into_result(status, || Self::from_handle(Handle(handle)))
135 }
136 }
137
138 /// Attempt to queue a user packet to the IO port.
139 ///
140 /// Wraps the
141 /// [mx_port_queue](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/port_queue.md)
142 /// syscall.
143 pub fn queue(&self, packet: &Packet) -> Result<(), Status> {
144 let status = unsafe {
145 sys::mx_port_queue(self.raw_handle(),
146 &packet.0 as *const sys::mx_port_packet_t as *const u8, 0)
147 };
148 into_result(status, || ())
149 }
150
151 /// Wait for a packet to arrive on a (V2) port.
152 ///
153 /// Wraps the
154 /// [mx_port_wait](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/port_wait2.md)
155 /// syscall.
156 pub fn wait(&self, deadline: Time) -> Result<Packet, Status> {
157 let mut packet = Default::default();
158 let status = unsafe {
159 sys::mx_port_wait(self.raw_handle(), deadline,
160 &mut packet as *mut sys::mx_port_packet_t as *mut u8, 0)
161 };
162 into_result(status, || Packet(packet))
163 }
164
165 /// Cancel pending wait_async calls for an object with the given key.
166 ///
167 /// Wraps the
168 /// [mx_port_cancel](https://fuchsia.googlesource.com/magenta/+/HEAD/docs/syscalls/port_cancel.md)
169 /// syscall.
170 pub fn cancel<H>(&self, source: &H, key: u64) -> Result<(), Status> where H: HandleBase {
171 let status = unsafe {
172 sys::mx_port_cancel(self.raw_handle(), source.raw_handle(), key)
173 };
174 into_result(status, || ())
175 }
176}
177
178/// Options for creating a port.
179#[repr(u32)]
180#[derive(Debug, Copy, Clone, Eq, PartialEq)]
181pub enum PortOpts {
182 /// Default options.
183 Default = 0,
184}
185
186impl Default for PortOpts {
187 fn default() -> Self {
188 PortOpts::Default
189 }
190}
191
192/// Options for wait_async.
193#[repr(u32)]
194#[derive(Debug, Copy, Clone, Eq, PartialEq)]
195pub enum WaitAsyncOpts {
196 Once = sys::MX_WAIT_ASYNC_ONCE,
197 Repeating = sys::MX_WAIT_ASYNC_REPEATING,
198}
199
200#[cfg(test)]
201mod tests {
202 use super::*;
203 use {Duration, Event, EventOpts};
204 use {MX_SIGNAL_LAST_HANDLE, MX_SIGNAL_NONE, MX_USER_SIGNAL_0, MX_USER_SIGNAL_1};
205 use deadline_after;
206
207 #[test]
208 fn port_basic() {
209 let ten_ms: Duration = 10_000_000;
210
211 let port = Port::create(PortOpts::Default).unwrap();
212
213 // Waiting now should time out.
214 assert_eq!(port.wait(deadline_after(ten_ms)), Err(Status::ErrTimedOut));
215
216 // Send a valid packet.
217 let packet = Packet::from_user_packet(
218 42,
219 123,
220 UserPacket::from_u8_array([13; 32]),
221 );
222 assert!(port.queue(&packet).is_ok());
223
224 // Waiting should succeed this time. We should get back the packet we sent.
225 let read_packet = port.wait(deadline_after(ten_ms)).unwrap();
226 assert_eq!(read_packet, packet);
227 }
228
229 #[test]
230 fn wait_async_once() {
231 let ten_ms: Duration = 10_000_000;
232 let key = 42;
233
234 let port = Port::create(PortOpts::Default).unwrap();
235 let event = Event::create(EventOpts::Default).unwrap();
236
237 assert!(event.wait_async(&port, key, MX_USER_SIGNAL_0 | MX_USER_SIGNAL_1,
238 WaitAsyncOpts::Once).is_ok());
239
240 // Waiting without setting any signal should time out.
241 assert_eq!(port.wait(deadline_after(ten_ms)), Err(Status::ErrTimedOut));
242
243 // If we set a signal, we should be able to wait for it.
244 assert!(event.signal(MX_SIGNAL_NONE, MX_USER_SIGNAL_0).is_ok());
245 let read_packet = port.wait(deadline_after(ten_ms)).unwrap();
246 assert_eq!(read_packet.key(), key);
247 assert_eq!(read_packet.status(), 0);
248 match read_packet.contents() {
249 PacketContents::SignalOne(sig) => {
250 assert_eq!(sig.trigger(), MX_USER_SIGNAL_0 | MX_USER_SIGNAL_1);
251 assert_eq!(sig.observed(), MX_USER_SIGNAL_0 | MX_SIGNAL_LAST_HANDLE);
252 assert_eq!(sig.count(), 1);
253 }
254 _ => panic!("wrong packet type"),
255 }
256
257 // Shouldn't get any more packets.
258 assert_eq!(port.wait(deadline_after(ten_ms)), Err(Status::ErrTimedOut));
259
260 // Calling wait_async again should result in another packet.
261 assert!(event.wait_async(&port, key, MX_USER_SIGNAL_0, WaitAsyncOpts::Once).is_ok());
262 let read_packet = port.wait(deadline_after(ten_ms)).unwrap();
263 assert_eq!(read_packet.key(), key);
264 assert_eq!(read_packet.status(), 0);
265 match read_packet.contents() {
266 PacketContents::SignalOne(sig) => {
267 assert_eq!(sig.trigger(), MX_USER_SIGNAL_0);
268 assert_eq!(sig.observed(), MX_USER_SIGNAL_0 | MX_SIGNAL_LAST_HANDLE);
269 assert_eq!(sig.count(), 1);
270 }
271 _ => panic!("wrong packet type"),
272 }
273
274 // Calling wait_async then cancel, we should not get a packet as cancel will remove it from
275 // the queue.
276 assert!(event.wait_async(&port, key, MX_USER_SIGNAL_0, WaitAsyncOpts::Once).is_ok());
277 assert!(port.cancel(&event, key).is_ok());
278 assert_eq!(port.wait(deadline_after(ten_ms)), Err(Status::ErrTimedOut));
279
280 // If the event is signalled after the cancel, we also shouldn't get a packet.
281 assert!(event.signal(MX_USER_SIGNAL_0, MX_SIGNAL_NONE).is_ok()); // clear signal
282 assert!(event.wait_async(&port, key, MX_USER_SIGNAL_0, WaitAsyncOpts::Once).is_ok());
283 assert!(port.cancel(&event, key).is_ok());
284 assert!(event.signal(MX_SIGNAL_NONE, MX_USER_SIGNAL_0).is_ok());
285 assert_eq!(port.wait(deadline_after(ten_ms)), Err(Status::ErrTimedOut));
286 }
287
288 #[test]
289 fn wait_async_repeating() {
290 let ten_ms: Duration = 10_000_000;
291 let key = 42;
292
293 let port = Port::create(PortOpts::Default).unwrap();
294 let event = Event::create(EventOpts::Default).unwrap();
295
296 assert!(event.wait_async(&port, key, MX_USER_SIGNAL_0 | MX_USER_SIGNAL_1,
297 WaitAsyncOpts::Repeating).is_ok());
298
299 // Waiting without setting any signal should time out.
300 assert_eq!(port.wait(deadline_after(ten_ms)), Err(Status::ErrTimedOut));
301
302 // If we set a signal, we should be able to wait for it.
303 assert!(event.signal(MX_SIGNAL_NONE, MX_USER_SIGNAL_0).is_ok());
304 let read_packet = port.wait(deadline_after(ten_ms)).unwrap();
305 assert_eq!(read_packet.key(), key);
306 assert_eq!(read_packet.status(), 0);
307 match read_packet.contents() {
308 PacketContents::SignalRep(sig) => {
309 assert_eq!(sig.trigger(), MX_USER_SIGNAL_0 | MX_USER_SIGNAL_1);
310 assert_eq!(sig.observed(), MX_USER_SIGNAL_0 | MX_SIGNAL_LAST_HANDLE);
311 assert_eq!(sig.count(), 1);
312 }
313 _ => panic!("wrong packet type"),
314 }
315
316 // Should not get any more packets, as MX_WAIT_ASYNC_REPEATING is edge triggered rather than
317 // level triggered.
318 assert_eq!(port.wait(deadline_after(ten_ms)), Err(Status::ErrTimedOut));
319
320 // If we clear and resignal, we should get the same packet again,
321 // even though we didn't call event.wait_async again.
322 assert!(event.signal(MX_USER_SIGNAL_0, MX_SIGNAL_NONE).is_ok()); // clear signal
323 assert!(event.signal(MX_SIGNAL_NONE, MX_USER_SIGNAL_0).is_ok());
324 let read_packet = port.wait(deadline_after(ten_ms)).unwrap();
325 assert_eq!(read_packet.key(), key);
326 assert_eq!(read_packet.status(), 0);
327 match read_packet.contents() {
328 PacketContents::SignalRep(sig) => {
329 assert_eq!(sig.trigger(), MX_USER_SIGNAL_0 | MX_USER_SIGNAL_1);
330 assert_eq!(sig.observed(), MX_USER_SIGNAL_0 | MX_SIGNAL_LAST_HANDLE);
331 assert_eq!(sig.count(), 1);
332 }
333 _ => panic!("wrong packet type"),
334 }
335
336 // Cancelling the wait should stop us getting packets...
337 assert!(port.cancel(&event, key).is_ok());
338 assert_eq!(port.wait(deadline_after(ten_ms)), Err(Status::ErrTimedOut));
339 // ... even if we clear and resignal
340 assert!(event.signal(MX_USER_SIGNAL_0, MX_SIGNAL_NONE).is_ok()); // clear signal
341 assert!(event.signal(MX_SIGNAL_NONE, MX_USER_SIGNAL_0).is_ok());
342 assert_eq!(port.wait(deadline_after(ten_ms)), Err(Status::ErrTimedOut));
343
344 // Calling wait_async again should result in another packet.
345 assert!(event.wait_async(&port, key, MX_USER_SIGNAL_0, WaitAsyncOpts::Repeating).is_ok());
346 let read_packet = port.wait(deadline_after(ten_ms)).unwrap();
347 assert_eq!(read_packet.key(), key);
348 assert_eq!(read_packet.status(), 0);
349 match read_packet.contents() {
350 PacketContents::SignalRep(sig) => {
351 assert_eq!(sig.trigger(), MX_USER_SIGNAL_0);
352 assert_eq!(sig.observed(), MX_USER_SIGNAL_0 | MX_SIGNAL_LAST_HANDLE);
353 assert_eq!(sig.count(), 1);
354 }
355 _ => panic!("wrong packet type"),
356 }
357
358 // Closing the handle should stop us getting packets.
359 drop(event);
360 assert_eq!(port.wait(deadline_after(ten_ms)), Err(Status::ErrTimedOut));
361 }
362}