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 unbind_port(&self, port: &Port) -> Result<(), Status> {
53 let options = sys::ZX_INTERRUPT_UNBIND;
54 let status =
57 unsafe { sys::zx_interrupt_bind(self.raw_handle(), port.raw_handle(), 0, options) };
58 ok(status)
59 }
60
61 pub fn wait(&self) -> Result<Instant<T>, Status> {
65 let mut timestamp = 0;
66 let status = unsafe { sys::zx_interrupt_wait(self.raw_handle(), &mut timestamp) };
68 ok(status)?;
69 Ok(Instant::from_nanos(timestamp))
70 }
71
72 pub fn ack(&self) -> Result<(), Status> {
76 let status = unsafe { sys::zx_interrupt_ack(self.raw_handle()) };
78 ok(status)
79 }
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 delegated_concrete_handle_based_impls!(|h| Self(h, PhantomData));
91}
92
93pub trait InterruptTimeline: Timeline {
94 const CREATE_FLAGS: u32;
95}
96
97impl InterruptTimeline for MonotonicTimeline {
98 const CREATE_FLAGS: u32 = sys::ZX_INTERRUPT_TIMESTAMP_MONO;
99}
100
101impl InterruptTimeline for BootTimeline {
102 const CREATE_FLAGS: u32 = 0;
103}
104
105impl<T: InterruptTimeline> Interrupt<VirtualInterruptKind, T> {
106 pub fn create_virtual() -> Result<Self, Status> {
110 let handle = unsafe {
112 let mut handle = sys::ZX_HANDLE_INVALID;
113 ok(sys::zx_interrupt_create(
114 sys::ZX_HANDLE_INVALID,
115 T::CREATE_FLAGS,
116 sys::ZX_INTERRUPT_VIRTUAL,
117 &mut handle,
118 ))?;
119 NullableHandle::from_raw(handle)
120 };
121 Ok(Interrupt(handle, PhantomData))
122 }
123
124 pub fn trigger(&self, time: Instant<T>) -> Result<(), Status> {
128 let status = unsafe { sys::zx_interrupt_trigger(self.raw_handle(), 0, time.into_nanos()) };
130 ok(status)
131 }
132}
133
134impl<K: InterruptKind, T: Timeline> AsHandleRef for Interrupt<K, T> {
135 fn as_handle_ref(&self) -> HandleRef<'_> {
136 self.0.as_handle_ref()
137 }
138}
139
140impl<K: InterruptKind, T: Timeline> From<NullableHandle> for Interrupt<K, T> {
141 fn from(handle: NullableHandle) -> Self {
142 Interrupt::<K, T>(handle, PhantomData)
143 }
144}
145
146impl<K: InterruptKind, T: Timeline> From<Interrupt<K, T>> for NullableHandle {
147 fn from(x: Interrupt<K, T>) -> NullableHandle {
148 x.0
149 }
150}
151
152impl<K: InterruptKind, T: Timeline> HandleBased for Interrupt<K, T> {}
153
154mod private {
155 pub trait Sealed {}
156}
157
158#[cfg(test)]
159mod tests {
160 use zx_status::Status;
161
162 use crate::{
163 BootInstant, Interrupt, MonotonicInstant, MonotonicTimeline, Port, PortOptions,
164 VirtualInterrupt, VirtualInterruptKind,
165 };
166
167 #[test]
168 fn bind() {
169 let interrupt = VirtualInterrupt::create_virtual().unwrap();
170 let port = Port::create_with_opts(PortOptions::BIND_TO_INTERRUPT);
171 let key = 1;
172 let result = interrupt.bind_port(&port, key);
173 assert_eq!(result, Ok(()));
174
175 let result = interrupt.bind_port(&port, key);
177 assert_eq!(result, Err(Status::ALREADY_BOUND));
178
179 let result = interrupt.unbind_port(&port);
181 assert_eq!(result, Ok(()));
182 let result = interrupt.bind_port(&port, key);
183 assert_eq!(result, Ok(()));
184 }
185
186 #[test]
187 fn ack() {
188 let interrupt = VirtualInterrupt::create_virtual().unwrap();
189 let result = interrupt.ack();
190 assert_eq!(result.err(), Some(Status::BAD_STATE));
191 }
192
193 #[test]
194 fn trigger() {
195 let interrupt = VirtualInterrupt::create_virtual().unwrap();
196 let result = interrupt.trigger(BootInstant::from_nanos(10));
197 assert_eq!(result, Ok(()));
198 }
199
200 #[test]
201 fn trigger_monotimeline() {
202 let interrupt =
203 Interrupt::<VirtualInterruptKind, MonotonicTimeline>::create_virtual().unwrap();
204 let result = interrupt.trigger(MonotonicInstant::from_nanos(10));
205 assert_eq!(result, Ok(()));
206 }
207
208 #[test]
209 fn wait() {
210 let interrupt = VirtualInterrupt::create_virtual().unwrap();
211 let result = interrupt.trigger(BootInstant::from_nanos(10));
212 assert_eq!(result, Ok(()));
213 let instant = interrupt.wait().expect("wait failed");
214 assert_eq!(instant.into_nanos(), 10);
215 }
216
217 #[test]
218 fn wait_monotimeline() {
219 let interrupt =
220 Interrupt::<VirtualInterruptKind, MonotonicTimeline>::create_virtual().unwrap();
221 let result = interrupt.trigger(MonotonicInstant::from_nanos(10));
222 assert_eq!(result, Ok(()));
223 let instant = interrupt.wait().expect("wait failed");
224 assert_eq!(instant.into_nanos(), 10);
225 }
226
227 #[test]
228 fn destroy() {
229 let interrupt =
230 Interrupt::<VirtualInterruptKind, MonotonicTimeline>::create_virtual().unwrap();
231 assert_eq!(interrupt.destroy(), Ok(()));
232 }
233}