On Sun Jul 13, 2025 at 1:19 PM CEST, Benno Lossin wrote: > On Sun Jul 13, 2025 at 12:24 PM CEST, Danilo Krummrich wrote: >> On Sun Jul 13, 2025 at 1:32 AM CEST, Daniel Almeida wrote: >>> >>> >>>> On 12 Jul 2025, at 18:24, Danilo Krummrich <dakr@xxxxxxxxxx> wrote: >>>> >>>> On Thu Jul 3, 2025 at 9:30 PM CEST, Daniel Almeida wrote: >>>>> +/// Callbacks for an IRQ handler. >>>>> +pub trait Handler: Sync { >>>>> + /// The hard IRQ handler. >>>>> + /// >>>>> + /// This is executed in interrupt context, hence all corresponding >>>>> + /// limitations do apply. >>>>> + /// >>>>> + /// All work that does not necessarily need to be executed from >>>>> + /// interrupt context, should be deferred to a threaded handler. >>>>> + /// See also [`ThreadedRegistration`]. >>>>> + fn handle(&self) -> IrqReturn; >>>>> +} >>>> >>>> One thing I forgot, the IRQ handlers should have a &Device<Bound> argument, >>>> i.e.: >>>> >>>> fn handle(&self, dev: &Device<Bound>) -> IrqReturn >>>> >>>> IRQ registrations naturally give us this guarantee, so we should take advantage >>>> of that. >>>> >>>> - Danilo >>> >>> Hi Danilo, >>> >>> I do not immediately see a way to get a Device<Bound> from here: >>> >>> unsafe extern "C" fn handle_irq_callback<T: Handler>(_irq: i32, ptr: *mut c_void) -> c_uint { >>> >>> Refall that we've established `ptr` to be the address of the handler. This >>> came after some back and forth and after the extensive discussion that Benno >>> and Boqun had w.r.t to pinning in request_irq(). >> >> You can just wrap the Handler in a new type and store the pointer there: >> >> #[pin_data] >> struct Wrapper { >> #[pin] >> handler: T, >> dev: NonNull<Device<Bound>>, >> } >> >> And then pass a pointer to the Wrapper field to request_irq(); >> handle_irq_callback() can construct a &T and a &Device<Bound> from this. >> >> Note that storing a device pointer, without its own reference count, is >> perfectly fine, since inner (Devres<RegistrationInner>) already holds a >> reference to the device and guarantees the bound scope for the handler >> callbacks. > > Can't we just add an accessor function to `Devres`? #[pin_data] pub struct Registration<T: Handler + 'static> { #[pin] inner: Devres<RegistrationInner>, #[pin] handler: T, /// Pinned because we need address stability so that we can pass a pointer /// to the callback. #[pin] _pin: PhantomPinned, } Currently we pass the address of handler to request_irq(), so this doesn't help, hence my proposal to replace the above T with Wrapper (actually Wrapper<T>). > Also `Devres` only stores `Device<Normal>`, not `Device<Bound>`... The Devres instance itself may out-live device unbind, but it ensures that the encapsulated data does not, hence it holds a reference count, i.e. ARef<Device>. Device<Bound> or ARef<Device<Bound>> *never* exists, only &'a Device<Bound> within a corresponding scope for which we can guarantee the device is bound. In the proposed wrapper we can store a NonNull<Device<Bound>> though, because we can safely give out a &Device<Bound> in the IRQ's handle() callback. This is because: (1) RegistrationInner is guarded by Devres and guarantees that free_irq() is completed *before* the device is unbound. (2) It is guaranteed that the device pointer is valid because (1) guarantees it's even bound and because Devres<RegistrationInner> itself has a reference count.