1use crate::{
8 BootTimeline, Instant, MonotonicTimeline, NullableHandle, Port, Status, Timeline, ok, sys,
9};
10use std::marker::PhantomData;
11
12#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
16#[repr(transparent)]
17pub struct Interrupt<K = RealInterruptKind, T = BootTimeline>(NullableHandle, PhantomData<(K, T)>);
18
19impl_handle_based!(Interrupt, [K: InterruptKind, T: Timeline], [K, T]);
20
21pub trait InterruptKind: private::Sealed {}
22
23#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
24pub struct VirtualInterruptKind;
25
26impl InterruptKind for VirtualInterruptKind {}
27impl private::Sealed for VirtualInterruptKind {}
28
29#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
30pub struct RealInterruptKind;
31
32impl InterruptKind for RealInterruptKind {}
33impl private::Sealed for RealInterruptKind {}
34
35pub type VirtualInterrupt = Interrupt<VirtualInterruptKind>;
36
37impl<K: InterruptKind, T: Timeline> Interrupt<K, T> {
38 pub fn bind_port(&self, port: &Port, key: u64) -> Result<(), Status> {
42 let options = sys::ZX_INTERRUPT_BIND;
43 let status =
45 unsafe { sys::zx_interrupt_bind(self.raw_handle(), port.raw_handle(), key, options) };
46 ok(status)
47 }
48
49 pub fn unbind_port(&self, port: &Port) -> Result<(), Status> {
54 let options = sys::ZX_INTERRUPT_UNBIND;
55 let status =
58 unsafe { sys::zx_interrupt_bind(self.raw_handle(), port.raw_handle(), 0, options) };
59 ok(status)
60 }
61
62 pub fn wait(&self) -> Result<Instant<T>, Status> {
66 let mut timestamp = 0;
67 let status = unsafe { sys::zx_interrupt_wait(self.raw_handle(), &mut timestamp) };
69 ok(status)?;
70 Ok(Instant::from_nanos(timestamp))
71 }
72
73 pub fn ack(&self) -> Result<(), Status> {
77 let status = unsafe { sys::zx_interrupt_ack(self.raw_handle()) };
79 ok(status)
80 }
81 pub fn destroy(self) -> Result<(), Status> {
85 let status = unsafe { sys::zx_interrupt_destroy(self.raw_handle()) };
87 ok(status)
88 }
89}
90
91pub trait InterruptTimeline: Timeline {
92 const CREATE_FLAGS: u32;
93}
94
95impl InterruptTimeline for MonotonicTimeline {
96 const CREATE_FLAGS: u32 = sys::ZX_INTERRUPT_TIMESTAMP_MONO;
97}
98
99impl InterruptTimeline for BootTimeline {
100 const CREATE_FLAGS: u32 = 0;
101}
102
103impl<T: InterruptTimeline> Interrupt<VirtualInterruptKind, T> {
104 pub fn create_virtual() -> Result<Self, Status> {
108 let handle = unsafe {
110 let mut handle = sys::ZX_HANDLE_INVALID;
111 ok(sys::zx_interrupt_create(
112 sys::ZX_HANDLE_INVALID,
113 T::CREATE_FLAGS,
114 sys::ZX_INTERRUPT_VIRTUAL,
115 &mut handle,
116 ))?;
117 NullableHandle::from_raw(handle)
118 };
119 Ok(Interrupt(handle, PhantomData))
120 }
121
122 pub fn trigger(&self, time: Instant<T>) -> Result<(), Status> {
126 let status = unsafe { sys::zx_interrupt_trigger(self.raw_handle(), 0, time.into_nanos()) };
128 ok(status)
129 }
130}
131
132mod private {
133 pub trait Sealed {}
134}
135
136#[cfg(test)]
137mod tests {
138 use zx_status::Status;
139
140 use crate::{
141 BootInstant, Interrupt, MonotonicInstant, MonotonicTimeline, Port, PortOptions,
142 VirtualInterrupt, VirtualInterruptKind,
143 };
144
145 #[test]
146 fn bind() {
147 let interrupt = VirtualInterrupt::create_virtual().unwrap();
148 let port = Port::create_with_opts(PortOptions::BIND_TO_INTERRUPT);
149 let key = 1;
150 let result = interrupt.bind_port(&port, key);
151 assert_eq!(result, Ok(()));
152
153 let result = interrupt.bind_port(&port, key);
155 assert_eq!(result, Err(Status::ALREADY_BOUND));
156
157 let result = interrupt.unbind_port(&port);
159 assert_eq!(result, Ok(()));
160 let result = interrupt.bind_port(&port, key);
161 assert_eq!(result, Ok(()));
162 }
163
164 #[test]
165 fn ack() {
166 let interrupt = VirtualInterrupt::create_virtual().unwrap();
167 let result = interrupt.ack();
168 assert_eq!(result.err(), Some(Status::BAD_STATE));
169 }
170
171 #[test]
172 fn trigger() {
173 let interrupt = VirtualInterrupt::create_virtual().unwrap();
174 let result = interrupt.trigger(BootInstant::from_nanos(10));
175 assert_eq!(result, Ok(()));
176 }
177
178 #[test]
179 fn trigger_monotimeline() {
180 let interrupt =
181 Interrupt::<VirtualInterruptKind, MonotonicTimeline>::create_virtual().unwrap();
182 let result = interrupt.trigger(MonotonicInstant::from_nanos(10));
183 assert_eq!(result, Ok(()));
184 }
185
186 #[test]
187 fn wait() {
188 let interrupt = VirtualInterrupt::create_virtual().unwrap();
189 let result = interrupt.trigger(BootInstant::from_nanos(10));
190 assert_eq!(result, Ok(()));
191 let instant = interrupt.wait().expect("wait failed");
192 assert_eq!(instant.into_nanos(), 10);
193 }
194
195 #[test]
196 fn wait_monotimeline() {
197 let interrupt =
198 Interrupt::<VirtualInterruptKind, MonotonicTimeline>::create_virtual().unwrap();
199 let result = interrupt.trigger(MonotonicInstant::from_nanos(10));
200 assert_eq!(result, Ok(()));
201 let instant = interrupt.wait().expect("wait failed");
202 assert_eq!(instant.into_nanos(), 10);
203 }
204
205 #[test]
206 fn destroy() {
207 let interrupt =
208 Interrupt::<VirtualInterruptKind, MonotonicTimeline>::create_virtual().unwrap();
209 assert_eq!(interrupt.destroy(), Ok(()));
210 }
211}