To use async::IrqMethod, zx::interrupt, and fit::defer, add the following to your build file (though some may be included transitively by other driver dependencies):
GN:
deps = [ "//sdk/lib/async:async-cpp", # For `async::IrqMethod` "//sdk/lib/fit", # For `fit::defer` "//zircon/system/ulib/zx", # For `zx::interrupt` ]
Bazel:
deps = [ "@fuchsia_sdk//pkg/async-cpp", # For `async::IrqMethod` "@fuchsia_sdk//pkg/fit", # For `fit::defer` "@fuchsia_sdk//pkg/zx", # For `zx::interrupt` ]
Drivers typically acquire an interrupt object from a FIDL service.
A driver might request a GPIO interrupt via fuchsia.hardware.gpio/Gpio.GetInterrupt.
The driver typically uses the Platform Device service to acquire it via methods like GetInterruptById or GetInterruptByName on the fuchsia.hardware.platform.device/Device protocol.
Lifecycle and Cleanup: No manual cleanup of the interrupt handle is necessary. The zx::interrupt wrapper manages the handle's lifecycle; its destructor automatically closes the handle when the object goes out of scope.
async::IrqMethod to listen to interrupts.fit::defer to ensure the interrupt is acknowledged (interrupt_.ack()) even if errors occur, to re-arm the interrupt.// Contains `driver_base2.h`. #include <lib/driver/component/cpp/driver_base2.h> // Contains `async::IrqMethod`. #include <lib/async/cpp/irq.h> // Contains `fit::defer`. #include <lib/fit/defer.h> // Contains `zx::interrupt`. #include <lib/zx/interrupt.h> class MyDriver : public fdf::DriverBase2 { public: zx::result<> Start(fdf::DriverContext context) override { // ... Connect to FIDL service and get interrupt handle ... // interrupt_ = std::move(interrupt->value()->interrupt); interrupt_handler_.set_object(interrupt_.get()); zx_status_t status = interrupt_handler_.Begin(dispatcher()); if (status != ZX_OK) { return zx::error(status); } return zx::ok(); } private: void HandleInterrupt(async_dispatcher_t* dispatcher, async::IrqBase* irq, zx_status_t status, const zx_packet_interrupt_t* interrupt_packet) { if (status != ZX_OK) { return; } // Use defer to ensure the interrupt is acknowledged on all exit paths. // Failing to ack will prevent future interrupts from firing. auto ack_interrupt = fit::defer([this] { interrupt_.ack(); }); // Perform work in response to triggered interrupt. } zx::interrupt interrupt_; async::IrqMethod<MyDriver, &MyDriver::HandleInterrupt> interrupt_handler_{this}; };
interrupt_.ack() will prevent the interrupt from triggering again. Use fit::defer as shown in the example to avoid this.Begin(). If the handler blocks or performs heavy computation, it will starve other tasks on that dispatcher. Offload heavy work to a separate thread or use asynchronous primitives if necessary.ZX_VIRTUAL_INTERRUPT_UNTRIGGERED signal.