1use crate::{
8 AsHandleRef, BootTimeline, HandleBased, HandleRef, Instant, MonotonicTimeline, NullableHandle,
9 Port, Status, Timeline, ok, sys,
10};
11use std::marker::PhantomData;
12
13#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
17#[repr(transparent)]
18pub struct Interrupt<K = RealInterruptKind, T = BootTimeline>(NullableHandle, PhantomData<(K, T)>);
19
20pub trait InterruptKind: private::Sealed {}
21
22#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
23pub struct VirtualInterruptKind;
24
25impl InterruptKind for VirtualInterruptKind {}
26impl private::Sealed for VirtualInterruptKind {}
27
28#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
29pub struct RealInterruptKind;
30
31impl InterruptKind for RealInterruptKind {}
32impl private::Sealed for RealInterruptKind {}
33
34pub type VirtualInterrupt = Interrupt<VirtualInterruptKind>;
35
36impl<K: InterruptKind, T: Timeline> Interrupt<K, T> {
37 pub fn bind_port(&self, port: &Port, key: u64) -> Result<(), Status> {
41 let options = sys::ZX_INTERRUPT_BIND;
42 let status =
44 unsafe { sys::zx_interrupt_bind(self.raw_handle(), port.raw_handle(), key, options) };
45 ok(status)
46 }
47
48 pub fn ack(&self) -> Result<(), Status> {
52 let status = unsafe { sys::zx_interrupt_ack(self.raw_handle()) };
54 ok(status)
55 }
56}
57
58pub trait InterruptTimeline: Timeline {
59 const CREATE_FLAGS: u32;
60}
61
62impl InterruptTimeline for MonotonicTimeline {
63 const CREATE_FLAGS: u32 = sys::ZX_INTERRUPT_TIMESTAMP_MONO;
64}
65
66impl InterruptTimeline for BootTimeline {
67 const CREATE_FLAGS: u32 = 0;
68}
69
70impl<T: InterruptTimeline> Interrupt<VirtualInterruptKind, T> {
71 pub fn create_virtual() -> Result<Self, Status> {
75 let handle = unsafe {
77 let mut handle = sys::ZX_HANDLE_INVALID;
78 ok(sys::zx_interrupt_create(
79 sys::ZX_HANDLE_INVALID,
80 T::CREATE_FLAGS,
81 sys::ZX_INTERRUPT_VIRTUAL,
82 &mut handle,
83 ))?;
84 NullableHandle::from_raw(handle)
85 };
86 Ok(Interrupt(handle, PhantomData))
87 }
88
89 pub fn trigger(&self, time: Instant<T>) -> Result<(), Status> {
93 let status = unsafe { sys::zx_interrupt_trigger(self.raw_handle(), 0, time.into_nanos()) };
95 ok(status)
96 }
97}
98
99impl<K: InterruptKind, T: Timeline> AsHandleRef for Interrupt<K, T> {
100 fn as_handle_ref(&self) -> HandleRef<'_> {
101 self.0.as_handle_ref()
102 }
103}
104
105impl<K: InterruptKind, T: Timeline> From<NullableHandle> for Interrupt<K, T> {
106 fn from(handle: NullableHandle) -> Self {
107 Interrupt::<K, T>(handle, PhantomData)
108 }
109}
110
111impl<K: InterruptKind, T: Timeline> From<Interrupt<K, T>> for NullableHandle {
112 fn from(x: Interrupt<K, T>) -> NullableHandle {
113 x.0
114 }
115}
116
117impl<K: InterruptKind> HandleBased for Interrupt<K> {}
118
119mod private {
120 pub trait Sealed {}
121}
122
123#[cfg(test)]
124mod tests {
125 use zx_status::Status;
126
127 use crate::{
128 BootInstant, Interrupt, MonotonicInstant, MonotonicTimeline, Port, PortOptions,
129 VirtualInterrupt, VirtualInterruptKind,
130 };
131
132 #[test]
133 fn bind() {
134 let interrupt = VirtualInterrupt::create_virtual().unwrap();
135 let port = Port::create_with_opts(PortOptions::BIND_TO_INTERRUPT);
136 let key = 1;
137 let result = interrupt.bind_port(&port, key);
138 assert_eq!(result, Ok(()));
139 }
140
141 #[test]
142 fn ack() {
143 let interrupt = VirtualInterrupt::create_virtual().unwrap();
144 let result = interrupt.ack();
145 assert_eq!(result.err(), Some(Status::BAD_STATE));
146 }
147
148 #[test]
149 fn trigger() {
150 let interrupt = VirtualInterrupt::create_virtual().unwrap();
151 let result = interrupt.trigger(BootInstant::from_nanos(10));
152 assert_eq!(result, Ok(()));
153 }
154
155 #[test]
156 fn trigger_monotimeline() {
157 let interrupt =
158 Interrupt::<VirtualInterruptKind, MonotonicTimeline>::create_virtual().unwrap();
159 let result = interrupt.trigger(MonotonicInstant::from_nanos(10));
160 assert_eq!(result, Ok(()));
161 }
162}