Skip to main content

cidre/mach/
message.rs

1use std::ffi::{c_uint, c_void};
2
3use crate::{
4    define_opts,
5    mach::{self, Boolean, Integer, KernReturn, Natural, Port, PortName},
6    os,
7};
8
9pub type Number = Natural;
10
11// https://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_msg.html
12
13define_opts!(pub HeaderBits(u32));
14impl HeaderBits {
15    pub const ZERO: Self = Self(0);
16
17    /// The value of MACH_MSGH_BITS_REMOTE determines the interpretation
18    /// of the msgh_remote_port field.  It is handled like a msgt_name,
19    /// but must result in a send or send-once type right.
20    pub const REMOTE_MASK: Self = Self(0x0000001f);
21
22    /// The value of MACH_MSGH_BITS_LOCAL determines the interpretation
23    /// of the msgh_local_port field.  It is handled like a msgt_name,
24    /// and also must result in a send or send-once type right.
25    pub const LOCAL_MASK: Self = Self(0x00001f00);
26
27    /// The value of MACH_MSGH_BITS_VOUCHER determines the interpretation
28    /// of the msgh_voucher_port field.  It is handled like a msgt_name,
29    /// but must result in a send right (and the msgh_voucher_port field
30    ///  must be the name of a send right to a Mach voucher kernel object.)
31    pub const VOUCHER_MASK: Self = Self(0x001f0000);
32
33    pub const PORTS_MASK: Self =
34        Self(Self::REMOTE_MASK.0 | Self::LOCAL_MASK.0 | Self::VOUCHER_MASK.0);
35
36    /// The kernel uses MACH_MSGH_BITS_COMPLEX as a hint.  If it isn't on, it
37    /// assumes the body of the message doesn't contain port rights or OOL
38    /// data.  The field is set in received messages.  A user task must
39    /// use caution in interpreting the body of a message if the bit isn't
40    /// on, because the mach_msg_type's in the body might "lie" about the
41    /// contents.  If the bit isn't on, but the mach_msg_types
42    /// in the body specify rights or OOL data, the behavior is undefined.
43    /// (Ie, an error may or may not be produced.)
44    pub const COMPLEX: Self = Self(0x80000000);
45    pub const USER: Self = Self(0x801f1f1f);
46    pub const RAISEIMP: Self = Self(0x20000000);
47    pub const DENAP: Self = Self::RAISEIMP;
48    pub const IMPHOLDASRT: Self = Self(0x10000000);
49    pub const DENAPHOLDASRT: Self = Self::IMPHOLDASRT;
50
51    /// should be zero; is is used internally.
52    pub const CIRCULAR: Self = Self(0x10000000);
53    pub const USED: Self = Self(0xb01f1f1f);
54
55    pub const fn with_ports(remote: TypeName, local: TypeName, voucher: TypeName) -> Self {
56        Self(
57            (remote as u32 & Self::REMOTE_MASK.0)
58                | (((local as u32) << 8) & Self::LOCAL_MASK.0)
59                | (((voucher as u32) << 16) & Self::VOUCHER_MASK.0),
60        )
61    }
62
63    pub const fn with(remote: TypeName, local: TypeName, voucher: TypeName, other: Self) -> Self {
64        Self(Self::with_ports(remote, local, voucher).0 | (other.0 & (!Self::PORTS_MASK.0)))
65    }
66}
67
68pub type Size = Natural;
69
70pub type Id = Integer;
71
72pub type Priority = c_uint;
73
74#[derive(Debug, Eq, PartialEq, Clone, Copy)]
75#[repr(u8)]
76pub enum TypeName {
77    None = 0,
78    PortName = 15,
79
80    /// The message will carry a receive right, and the caller must supply a receive right.
81    /// The caller loses the supplied receive right, but retains any send rights with the same name.
82    /// The make-send count and sequence number of the receive right are reset to zero and
83    /// no-more-senders notification requests are cancelled (with a send-once notification
84    /// being sent to the no-more-senders notification right), but the port retains other attributes
85    /// like queued messages and extant send and send-once rights. If a message carries a send
86    /// or send-once right, and the port dies while the message is in transit, then the receiving
87    ///  task will get MACH_PORT_DEAD instead of a right.
88    MoveRecieve = 16,
89
90    /// The message will carry a send right, and the caller must supply a send right.
91    /// The user reference count for the supplied send right is decremented, and
92    /// the right is destroyed if the count becomes zero. Unless a receive right remains,
93    /// the name becomes available for recycling. The caller may also supply a dead name,
94    /// which loses a user reference, and the receiving task will get MACH_PORT_DEAD.
95    MoveSend = 17,
96
97    /// The message will carry a send-once right, and the caller must supply a send-once right.
98    /// The caller loses the supplied send-once right. The caller may also supply a dead name,
99    ///  which loses a user reference, and the receiving task will get MACH_PORT_DEAD.
100    MoveSendOnce = 18,
101
102    /// The message will carry a send right, and the caller must supply a send right.
103    /// The user reference count for the supplied send right is not changed. The caller may also
104    /// supply a dead name and the receiving task will get MACH_PORT_DEAD.
105    CopySend = 19,
106
107    /// The message will carry a send right, but the caller must supply a receive right.
108    /// The send right is created from the receive right, and the receive right's make-send count
109    /// is incremented.
110    MakeSend = 20,
111
112    /// The message will carry a send-once right, but the caller must supply a receive right.
113    /// The send-once right is created from the receive right. Note that send once rights can
114    /// only be created from the receive right.
115    MakeSendOnce = 21,
116    CopyReceive = 22,
117    DisposeReceive = 24,
118    DisposeSend = 25,
119    DisposeSendOnce = 26,
120}
121
122impl TypeName {
123    /// This value is an alias for MACH_MSG_TYPE_MOVE_RECEIVE.
124    /// The message carried a receive right. If the receiving task already has send rights for the port,
125    /// then that name for the port will be reused; otherwise, the right will have a new,
126    /// previously unused name.
127    pub const PORT_RECEIVE: Self = Self::MoveRecieve;
128
129    /// This value is an alias for MACH_MSG_TYPE_MOVE_SEND.
130    /// The message carried a send right. If the receiving task already has send and/ or receive rights
131    /// for the port, then that name for the port will be reused. Otherwise, the right will have a new,
132    /// previously unused, name. If the task already has send rights, it gains a user reference
133    /// for the right (un- less this would cause the user-reference count to overflow).
134    /// Otherwise, it acquires send rights, with a user-reference count of one.
135    pub const PORT_SEND: Self = Self::MoveSend;
136
137    /// This value is an alias for MACH_MSG_TYPE_MOVE_SEND_ONCE. The message carried a send-once right.
138    /// The right will have a new, previously unused, name.
139    pub const PORT_SEND_ONCE: Self = Self::MoveSendOnce;
140}
141
142#[derive(Debug, Eq, PartialEq, Clone, Copy)]
143#[repr(u8)]
144pub enum CopyOpts {
145    PhysicalCopy = 0,
146    VirtualCopy = 1,
147    Allocate = 2,
148    Overwrite = 3,
149    KallocCopy = 4,
150}
151
152#[derive(Debug, Eq, PartialEq, Clone, Copy)]
153#[repr(u16)]
154pub enum GuardFlags {
155    None,
156    ImmovableReceive,
157    UnguardedOnSend,
158}
159
160impl GuardFlags {
161    pub const MASK: u16 = 3;
162}
163
164#[derive(Debug, Eq, PartialEq, Clone, Copy)]
165#[repr(u8)]
166pub enum DescType {
167    Port,
168
169    /// Out of line
170    Ool,
171    OolPorts,
172    OolVolatile,
173    GuardedPort,
174}
175
176impl DescType {
177    pub const MAX: Self = Self::GuardedPort;
178}
179
180#[doc(alias = "mach_msg_type_descriptor_t")]
181#[repr(C, packed(4))]
182pub struct TypeDesc {
183    pub pad1: Natural,
184    pub pad2: Size,
185    pub pad3: [u8; 3],
186    pub type_: DescType,
187}
188
189#[doc(alias = "mach_msg_port_descriptor_t")]
190#[repr(C, packed(4))]
191pub struct PortDesc {
192    pub name: Port,
193    pub pad1: Size,
194    pub pad2: u16,
195    pub disposition: TypeName,
196    pub type_: DescType,
197}
198
199#[doc(alias = "mach_msg_ool_descriptor32_t")]
200#[repr(C, packed(4))]
201pub struct OolDesc32 {
202    pub address: u32,
203    pub size: Size,
204    pub deallocate: Boolean,
205    pub pad1: u32,
206    pub type_: DescType,
207}
208
209#[doc(alias = "mach_msg_ool_descriptor64_t")]
210#[repr(C, packed(4))]
211pub struct OolDesc64 {
212    pub address: u64,
213    pub size: Size,
214    pub deallocate: Boolean,
215    pub pad1: u32,
216    pub type_: DescType,
217}
218
219#[doc(alias = "mach_msg_ool_descriptor_t")]
220#[repr(C, packed(4))]
221pub struct OolDesc {
222    pub address: *mut c_void,
223    pub deallocate: u8,
224    pub copy: CopyOpts,
225    pub pad1: u8,
226    pub type_: DescType,
227    pub size: Size,
228}
229
230#[derive(Debug, Copy, Clone)]
231#[doc(alias = "mach_msg_body_t")]
232#[repr(C, packed(4))]
233pub struct Body {
234    pub descriptor_count: Size,
235}
236
237#[derive(Debug, Copy, Clone)]
238#[doc(alias = "mach_msg_header_t")]
239#[repr(C, packed(4))]
240pub struct Header {
241    pub bits: HeaderBits,
242    pub size: Size,
243    pub remote_port: Port,
244    pub local_port: Port,
245    pub voucher_port: PortName,
246    pub id: Id,
247}
248
249#[doc(alias = "mach_msg_base_t")]
250#[repr(C, packed(4))]
251pub struct Base {
252    pub header: Header,
253    pub body: Body,
254}
255
256#[doc(alias = "mach_msg_trailer_size_t")]
257pub type TrailerSize = u32;
258
259#[derive(Debug, Copy, Clone)]
260#[doc(alias = "mach_msg_trailer_type_t")]
261#[repr(u32)]
262pub enum TrailerType {
263    Format0,
264}
265
266#[derive(Debug, Copy, Clone)]
267#[doc(alias = "mach_msg_trailer_t")]
268#[repr(C, packed(4))]
269pub struct Trailer {
270    pub type_: TrailerType,
271    pub size: TrailerSize,
272}
273
274/// Check errors with mach::msg_err
275pub type Return = KernReturn;
276
277pub mod err {
278    use crate::os::Error;
279
280    #[doc(alias = "MACH_MSG_MASK")]
281    pub const MASK: Error = Error::new_unchecked(0x00003e00);
282
283    /// No room in IPC name space for another capability name.
284    #[doc(alias = "MACH_MSG_IPC_SPACE")]
285    pub const IPC_SPACE: Error = Error::new_unchecked(0x00002000);
286
287    ///  No room in VM address space for out-of-line memory.
288    #[doc(alias = "MACH_MSG_VM_SPACE")]
289    pub const VM_SPACE: Error = Error::new_unchecked(0x00001000);
290
291    /// Kernel resource shortage handling an IPC capability.
292    #[doc(alias = "MACH_MSG_IPC_KERNEL")]
293    pub const IPC_KERNEL: Error = Error::new_unchecked(0x00000800);
294
295    /// Kernel resource shortage handling out-of-line memory.
296    #[doc(alias = "MACH_MSG_VM_KERNEL")]
297    pub const VM_KERNEL: Error = Error::new_unchecked(0x00000400);
298
299    /// Thread is waiting to send.  (Internal use only.)
300    #[doc(alias = "MACH_SEND_IN_PROGRESS")]
301    pub const SEND_IN_PROGRESS: Error = Error::new_unchecked(0x10000001);
302
303    /// Bogus in-line data.
304    #[doc(alias = "MACH_SEND_INVALID_DATA")]
305    pub const SEND_INVALID_DATA: Error = Error::new_unchecked(0x10000002);
306
307    /// Bogus destination port.
308    #[doc(alias = "MACH_SEND_INVALID_DEST")]
309    pub const SEND_INVALID_DEST: Error = Error::new_unchecked(0x10000003);
310
311    /// Message not sent before timeout expired.
312    #[doc(alias = "MACH_SEND_TIMED_OUT")]
313    pub const SEND_TIMED_OUT: Error = Error::new_unchecked(0x10000004);
314
315    /// Bogus voucher port.
316    #[doc(alias = "MACH_SEND_INVALID_VOUCHER")]
317    pub const SEND_INVALID_VOUCHER: Error = Error::new_unchecked(0x10000005);
318
319    /// Software interrupt.
320    #[doc(alias = "MACH_SEND_INTERRUPTED")]
321    pub const SEND_INTERRUPTED: Error = Error::new_unchecked(0x10000007);
322
323    /// Data doesn't contain a complete message.
324    #[doc(alias = "MACH_SEND_MSG_TOO_SMALL")]
325    pub const SEND_SEND_MSG_TOO_SMALL: Error = Error::new_unchecked(0x10000008);
326
327    ///  Bogus reply port.
328    #[doc(alias = "MACH_SEND_INVALID_REPLY")]
329    pub const SEND_INVALID_REPLY: Error = Error::new_unchecked(0x10000009);
330
331    /// Bogus port rights in the message body.
332    #[doc(alias = "MACH_SEND_INVALID_RIGHT")]
333    pub const SEND_INVALID_RIGHT: Error = Error::new_unchecked(0x1000000a);
334
335    /// Bogus notify port argument.
336    #[doc(alias = "MACH_SEND_INVALID_NOTIFY")]
337    pub const SEND_INVALID_NOTIFY: Error = Error::new_unchecked(0x1000000b);
338
339    /// Invalid out-of-line memory pointer.
340    #[doc(alias = "MACH_SEND_INVALID_MEMORY")]
341    pub const SEND_INVALID_MEMORY: Error = Error::new_unchecked(0x1000000c);
342
343    /// No message buffer is available.
344    #[doc(alias = "MACH_SEND_NO_BUFFER")]
345    pub const SEND_NO_BUFFER: Error = Error::new_unchecked(0x1000000d);
346
347    /// Send is too large for port
348    #[doc(alias = "MACH_SEND_TOO_LARGE")]
349    pub const SEND_TOO_LARGE: Error = Error::new_unchecked(0x1000000e);
350
351    /// Invalid msg-type specification.
352    #[doc(alias = "MACH_SEND_INVALID_TYPE")]
353    pub const SEND_INVALID_TYPE: Error = Error::new_unchecked(0x1000000f);
354
355    /// A field in the header had a bad value.
356    #[doc(alias = "MACH_SEND_INVALID_HEADER")]
357    pub const SEND_INVALID_HEADER: Error = Error::new_unchecked(0x10000010);
358
359    /// The trailer to be sent does not match kernel format.
360    #[doc(alias = "MACH_SEND_INVALID_TRAILER")]
361    pub const SEND_INVALID_TRAILER: Error = Error::new_unchecked(0x10000011);
362
363    /// The sending thread context did not match the context on the dest port
364    #[doc(alias = "MACH_SEND_INVALID_CONTEXT")]
365    pub const SEND_INVALID_CONTEXT: Error = Error::new_unchecked(0x10000012);
366
367    /// Send options are invalid.
368    #[doc(alias = "MACH_SEND_INVALID_OPTIONS")]
369    pub const SEND_INVALID_OPTIONS: Error = Error::new_unchecked(0x10000013);
370
371    /// Compatibility: no longer a returned error
372    #[doc(alias = "MACH_SEND_INVALID_RT_OOL_SIZE")]
373    pub const SEND_INVALID_RT_OOL_SIZE: Error = Error::new_unchecked(0x10000015);
374
375    /// The destination port doesn't accept ports in body
376    #[doc(alias = "MACH_SEND_NO_GRANT_DEST")]
377    pub const SEND_NO_GRANT_DEST: Error = Error::new_unchecked(0x10000016);
378
379    /// Message send was rejected by message filter
380    #[doc(alias = "MACH_SEND_MSG_FILTERED")]
381    pub const SEND_MSG_FILTERED: Error = Error::new_unchecked(0x10000017);
382
383    /// Message auxiliary data is too small
384    #[doc(alias = "MACH_SEND_AUX_TOO_SMALL")]
385    pub const SEND_AUX_TOO_SMALL: Error = Error::new_unchecked(0x10000018);
386
387    /// Message auxiliary data is too large
388    #[doc(alias = "MACH_SEND_AUX_TOO_LARGE")]
389    pub const SEND_SEND_AUX_TOO_LARGE: Error = Error::new_unchecked(0x10000019);
390
391    /// Thread is waiting for receive. (Internal use only.)
392    #[doc(alias = "MACH_RCV_IN_PROGRESS")]
393    pub const RCV_IN_PROGRESS: Error = Error::new_unchecked(0x10004001);
394
395    /// Bogus name for receive port/port-set.
396    #[doc(alias = "MACH_RCV_INVALID_NAME")]
397    pub const RCV_INVALID_NAME: Error = Error::new_unchecked(0x10004002);
398
399    /// Didn't get a message within the timeout value.
400    #[doc(alias = "MACH_RCV_TIMED_OUT")]
401    pub const RCV_TIMED_OUT: Error = Error::new_unchecked(0x10004003);
402
403    /// Message buffer is not large enough for inline data.
404    #[doc(alias = "MACH_RCV_TOO_LARGE")]
405    pub const RCV_TOO_LARGE: Error = Error::new_unchecked(0x10004004);
406
407    /// Software interrupt.    
408    #[doc(alias = "MACH_RCV_INTERRUPTED")]
409    pub const RCV_INTERRUPTED: Error = Error::new_unchecked(0x10004005);
410
411    /// compatibility: no longer a returned error
412    #[doc(alias = "MACH_RCV_PORT_CHANGED")]
413    pub const RCV_PORT_CHANGED: Error = Error::new_unchecked(0x10004006);
414
415    /// Bogus notify port argument.
416    #[doc(alias = "MACH_RCV_INVALID_NOTIFY")]
417    pub const RCV_INVALID_NOTIFY: Error = Error::new_unchecked(0x10004007);
418
419    /// Bogus message buffer for inline data.
420    #[doc(alias = "MACH_RCV_INVALID_DATA")]
421    pub const RCV_INVALID_DATA: Error = Error::new_unchecked(0x10004008);
422
423    /// Port/set was sent away/died during receive.
424    #[doc(alias = "MACH_RCV_PORT_DIED")]
425    pub const RCV_PORT_DIED: Error = Error::new_unchecked(0x10004009);
426
427    /// compatibility: no longer a returned error
428    #[doc(alias = "MACH_RCV_IN_SET")]
429    pub const RCV_IN_SET: Error = Error::new_unchecked(0x1000400a);
430
431    /// Error receiving message header.  See special bits.
432    #[doc(alias = "MACH_RCV_HEADER_ERROR")]
433    pub const RCV_HEADER_ERROR: Error = Error::new_unchecked(0x1000400b);
434
435    /// Error receiving message body.  See special bits.
436    #[doc(alias = "MACH_RCV_BODY_ERROR")]
437    pub const RCV_BODY_ERROR: Error = Error::new_unchecked(0x1000400c);
438
439    /// Invalid msg-type specification in scatter list.
440    #[doc(alias = "MACH_RCV_INVALID_TYPE")]
441    pub const RCV_INVALID_TYPE: Error = Error::new_unchecked(0x1000400d);
442
443    /// Out-of-line overwrite region is not large enough
444    #[doc(alias = "MACH_RCV_SCATTER_SMALL")]
445    pub const RCV_SCATTER_SMALL: Error = Error::new_unchecked(0x1000400e);
446
447    /// trailer type or number of trailer elements not supported
448    #[doc(alias = "MACH_RCV_INVALID_TRAILER")]
449    pub const RCV_INVALID_TRAILER: Error = Error::new_unchecked(0x1000400f);
450
451    /// Waiting for receive with timeout. (Internal use only.)
452    #[doc(alias = "MACH_RCV_IN_PROGRESS_TIMED")]
453    pub const RCV_IN_PROGRESS_TIMED: Error = Error::new_unchecked(0x10004011);
454
455    /// invalid reply port used in a STRICT_REPLY message    
456    #[doc(alias = "MACH_RCV_INVALID_REPLY")]
457    pub const RCV_INVALID_REPLY: Error = Error::new_unchecked(0x10004012);
458
459    /// invalid receive arguments, receive has not started
460    #[doc(alias = "MACH_RCV_INVALID_ARGUMENTS")]
461    pub const RCV_INVALID_ARGUMENTS: Error = Error::new_unchecked(0x10004013);
462}
463
464#[doc(alias = "mach_msg_empty_send_t")]
465#[derive(Debug, Copy, Clone)]
466#[repr(C, packed(4))]
467pub struct MsgEmptySend {
468    pub header: Header,
469}
470
471impl MsgEmptySend {
472    #[inline]
473    pub const fn with_remote_port(remote_port: mach::Port) -> Self {
474        Self {
475            header: Header {
476                bits: HeaderBits::with_ports(TypeName::CopySend, TypeName::None, TypeName::None),
477                size: std::mem::size_of::<Header>() as u32,
478                remote_port: remote_port,
479                local_port: mach::Port::NULL,
480                voucher_port: mach::Port::NULL,
481                id: 0,
482            },
483        }
484    }
485
486    #[inline]
487    pub fn send(&mut self) -> os::Result {
488        msg(
489            &mut self.header,
490            MsgOpt::SEND_MSG,
491            std::mem::size_of::<Self>() as u32,
492            0,
493            mach::Port::NULL,
494            Timeout::NONE,
495            mach::Port::NULL,
496        )
497        .result()
498    }
499
500    #[inline]
501    pub fn overwrite(&mut self) -> os::Result {
502        msg_overwrite(
503            &mut self.header,
504            MsgOpt::SEND_MSG,
505            std::mem::size_of::<Self>() as u32,
506            0,
507            mach::Port::NULL,
508            Timeout::NONE,
509            mach::Port::NULL,
510            std::ptr::null_mut(),
511            0,
512        )
513        .result()
514    }
515
516    #[inline]
517    pub fn send_to_remote(remote_port: mach::Port) -> os::Result {
518        Self::with_remote_port(remote_port).send()
519    }
520
521    #[inline]
522    pub fn overwrite_remote(remote_port: mach::Port) -> os::Result {
523        Self::with_remote_port(remote_port).overwrite()
524    }
525}
526
527#[doc(alias = "mach_msg_empty_rcv_t")]
528#[derive(Debug, Copy, Clone)]
529#[repr(C, packed(4))]
530pub struct MsgEmptyRcv {
531    pub header: Header,
532    pub trailer: Trailer,
533}
534
535#[doc(alias = "mach_msg_empty_t")]
536#[repr(C, packed(4))]
537pub union MsgEmpty {
538    pub send: MsgEmptySend,
539    pub rcv: MsgEmptyRcv,
540}
541
542define_opts!(
543    #[doc(alias = "mach_msg_option_t")]
544    pub MsgOpt(Integer)
545);
546
547impl MsgOpt {
548    #[doc(alias = "MACH_MSG_OPTION_NONE")]
549    pub const NONE: Self = Self(0x00000000);
550
551    #[doc(alias = "MACH_SEND_MSG")]
552    pub const SEND_MSG: Self = Self(0x00000001);
553
554    #[doc(alias = "MACH_RCV_MSG")]
555    pub const RCV_MSG: Self = Self(0x00000002);
556
557    /// report large message sizes
558    #[doc(alias = "MACH_RCV_LARGE")]
559    pub const RCV_LARGE: Self = Self(0x00000004);
560
561    /// identify source of large messages
562    #[doc(alias = "MACH_RCV_LARGE_IDENTITY")]
563    pub const RCV_LARGE_IDENTITY: Self = Self(0x00000008);
564
565    /// timeout value applies to send
566    #[doc(alias = "MACH_SEND_TIMEOUT")]
567    pub const SEND_TIMEOUT: Self = Self(0x00000010);
568
569    /// priority override for send
570    #[doc(alias = "MACH_SEND_OVERRIDE")]
571    pub const SEND_OVERRIDE: Self = Self(0x00000020);
572
573    /// don't restart interrupted sends
574    #[doc(alias = "MACH_SEND_INTERRUPT")]
575    pub const SEND_INTERRUPT: Self = Self(0x00000040);
576
577    /// arm send-possible notify
578    #[doc(alias = "MACH_SEND_NOTIFY")]
579    pub const SEND_NOTIFY: Self = Self(0x00000080);
580
581    /// ignore qlimits - kernel only
582    #[doc(alias = "MACH_SEND_ALWAYS")]
583    pub const SEND_ALWAYS: Self = Self(0x00010000);
584
585    /// rejection by message filter should return failure - user only
586    #[doc(alias = "MACH_SEND_FILTER_NONFATAL")]
587    pub const SEND_FILTER_NONFATA: Self = Self(0x00010000);
588
589    /// sender-provided trailer
590    #[doc(alias = "MACH_SEND_TRAILER")]
591    pub const SEND_TRAILER: Self = Self(0x00020000);
592
593    ///  msg won't carry importance
594    #[doc(alias = "MACH_SEND_NOIMPORTANCE")]
595    pub const SEND_NOIMPORTANCE: Self = Self(0x00040000);
596
597    #[doc(alias = "MACH_SEND_NODENAP")]
598    pub const SEND_NODENAP: Self = Self::SEND_NOIMPORTANCE;
599
600    /// msg carries importance - kernel only
601    #[doc(alias = "MACH_SEND_IMPORTANCE")]
602    pub const SEND_IMPORTANCE: Self = Self(0x00080000);
603
604    /// msg should do sync IPC override (on legacy kernels)
605    #[doc(alias = "MACH_SEND_SYNC_OVERRIDE")]
606    pub const SEND_SYNC_OVERRIDE: Self = Self(0x00100000);
607
608    /// IPC should propagate the caller's QoS
609    #[doc(alias = "MACH_SEND_PROPAGATE_QOS")]
610    pub const SEND_PROPAGATE_QOS: Self = Self(0x00200000);
611
612    // spub const SEND_SYNC_USE_THRPRI: Self = Self::SEND_PROPAGATE_QOS;
613
614    /// full send from kernel space - kernel only
615    #[doc(alias = "MACH_SEND_KERNEL")]
616    pub const SEND_KERNEL: Self = Self(0x00400000);
617
618    /// special reply port should boost thread doing sync bootstrap checkin
619    #[doc(alias = "MACH_SEND_SYNC_BOOTSTRAP_CHECKIN")]
620    pub const SEND_SYNC_BOOTSTRAP_CHECKIN: Self = Self(0x00800000);
621
622    /// timeout value applies to receive
623    #[doc(alias = "MACH_RCV_TIMEOUT")]
624    pub const RCV_TIMEOUT: Self = Self(0x00000100);
625
626    /// legacy name (value was: 0x00000200)
627    #[doc(alias = "MACH_RCV_NOTIFY")]
628    pub const RCV_NOTIFY: Self = Self(0x00000000);
629
630    /// don't restart interrupted receive
631    #[doc(alias = "MACH_RCV_INTERRUPT")]
632    pub const RCV_INTERRUPT: Self = Self(0x00000400);
633
634    /// willing to receive voucher port     
635    #[doc(alias = "MACH_RCV_VOUCHER")]
636    pub const RCV_VOUCHER: Self = Self(0x00000800);
637
638    // scatter receive (deprecated)
639    // pub const RCV_OVERWRITE: Self = Self(0x00000000);
640
641    /// Can receive new guarded descriptor
642    #[doc(alias = "MACH_RCV_GUARDED_DESC")]
643    pub const RCV_GUARDED_DESC: Self = Self(0x00001000);
644
645    /// sync waiter waiting for rcv
646    #[doc(alias = "MACH_RCV_SYNC_WAIT")]
647    pub const RCV_SYNC_WAIT: Self = Self(0x00004000);
648
649    /// sync waiter waiting to peek
650    #[doc = "MACH_RCV_SYNC_PEEK"]
651    pub const RCV_SYNC_PEEK: Self = Self(0x00008000);
652
653    /// Enforce specific properties about the reply port, and
654    /// the context in which a thread replies to a message
655    /// This flag must be passed on both the SEND and RCV
656    #[doc = "MACH_MSG_STRICT_REPLY"]
657    pub const MSG_STRICT_REPLY: Self = Self(0x00000200);
658}
659
660#[derive(Clone, Copy, Eq, PartialEq, Debug)]
661#[repr(transparent)]
662pub struct Timeout(pub Natural);
663
664impl Timeout {
665    pub const NONE: Self = Self(0);
666}
667
668#[doc(alias = "mach_msg")]
669#[inline]
670pub fn msg(
671    msg: &mut Header,
672    option: MsgOpt,
673    send_size: Size,
674    rcv_size: Size,
675    rcv_name: PortName,
676    timeout: Timeout,
677    notify: PortName,
678) -> Return {
679    unsafe { mach_msg(msg, option, send_size, rcv_size, rcv_name, timeout, notify) }
680}
681
682#[doc(alias = "mach_msg_overwrite")]
683#[inline]
684pub fn msg_overwrite(
685    msg: *mut Header,
686    option: MsgOpt,
687    send_size: Size,
688    rcv_size: Size,
689    rcv_name: PortName,
690    timeout: Timeout,
691    notify: PortName,
692    rcv_msg: *mut Header,
693    rcv_limit: Size,
694) -> Return {
695    unsafe {
696        mach_msg_overwrite(
697            msg, option, send_size, rcv_size, rcv_name, timeout, notify, rcv_msg, rcv_limit,
698        )
699    }
700}
701
702unsafe extern "C-unwind" {
703    fn mach_msg(
704        msg: *mut Header,
705        option: MsgOpt,
706        send_size: Size,
707        rcv_size: Size,
708        rcv_name: PortName,
709        timeout: Timeout,
710        notify: PortName,
711    ) -> Return;
712
713    fn mach_msg_overwrite(
714        msg: *mut Header,
715        option: MsgOpt,
716        send_size: Size,
717        rcv_size: Size,
718        rcv_name: PortName,
719        timeout: Timeout,
720        notify: PortName,
721        rcv_msg: *mut Header,
722        rcv_limit: Size,
723    ) -> Return;
724}