Testing with async::WaitMethod and using zx::interrupt requires async-cpp and zx:
GN:
deps = [ "//sdk/lib/async:async-cpp", # For `async::WaitMethod` "//zircon/system/ulib/zx", # For `zx::interrupt` ]
Bazel:
deps = [ "@fuchsia_sdk//pkg/async-cpp", # For `async::WaitMethod` "@fuchsia_sdk//pkg/zx", # For `zx::interrupt` ]
The test should create a virtual interrupt to provide to the driver.
zx::interrupt interrupt; ASSERT_EQ( zx::interrupt::create(zx::resource(), 0, ZX_INTERRUPT_VIRTUAL, &interrupt), ZX_OK);
Duplicate this interrupt and send the duplicate to the driver (usually via a fake FIDL service).
zx::interrupt duplicate; ASSERT_EQ(interrupt.duplicate(ZX_RIGHT_SAME_RIGHTS, &duplicate), ZX_OK);
The test can trigger a virtual interrupt like so:
ASSERT_EQ( interrupt.trigger(0, zx::clock::get_boot()), ZX_OK);
To verify that the driver has acknowledged the interrupt (by calling zx_interrupt_ack), the test can listen for the ZX_VIRTUAL_INTERRUPT_UNTRIGGERED signal.
When the driver acknowledges the interrupt, the system asserts this signal on the virtual interrupt object. The test can use async::WaitMethod to asynchronously wait for this signal on its handle of the interrupt.
// Contains `async::WaitMethod`. #include <lib/async/cpp/wait.h> // Contains `zx::interrupt`. #include <lib/zx/interrupt.h> // Contains `ZX_INTERRUPT_VIRTUAL`. #include <zircon/types.h> class MyDriverEnvironment : public fdf_testing::Environment { public: zx::result<> Serve(fdf::OutgoingDirectory& to_driver_vfs) override { zx::interrupt::create(zx::resource(), 0, ZX_INTERRUPT_VIRTUAL, &interrupt_); zx::interrupt duplicate; interrupt_.duplicate(ZX_RIGHT_SAME_RIGHTS, &duplicate); // Send duplicate to driver... async_dispatcher_t* dispatcher = fdf::Dispatcher::GetCurrent()->async_dispatcher(); interrupt_ack_handler_.set_object(interrupt_.get()); interrupt_ack_handler_.Begin(dispatcher); return zx::ok(); } private: void HandleInterruptAck(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status, const zx_packet_signal_t* signal) { if (status != ZX_OK) { FAIL(); } // Re-arm the listener. wait->Begin(dispatcher); } zx::interrupt interrupt_; async::WaitMethod<MyDriverEnvironment, &MyDriverEnvironment::HandleInterruptAck> interrupt_ack_handler_{this, ZX_HANDLE_INVALID, ZX_VIRTUAL_INTERRUPT_UNTRIGGERED, ZX_WAIT_ASYNC_EDGE}; };
HandleInterruptAck), you must call wait->Begin(dispatcher) to continue listening for subsequent acknowledgments. If you forget this, the test will only detect the first interrupt acknowledgment.async::Wait rely on the async dispatcher. If your test triggers an interrupt but doesn't run the dispatcher (e.g., via RunLoopUntilIdle or similar), the handler will never be called.ZX_VIRTUAL_INTERRUPT_UNTRIGGERED signal.