1 /// Check the `util` module to see how the `Card` structure is implemented. 2 pub mod utils; 3 4 use crate::utils::*; 5 use rustix::event::PollFlags; 6 use std::{ 7 io, 8 os::unix::io::{AsFd, OwnedFd}, 9 }; 10 11 impl Card { simulate_command_submission(&self) -> io::Result<OwnedFd>12 fn simulate_command_submission(&self) -> io::Result<OwnedFd> { 13 // Create a temporary syncobj to receive the command fence. 14 let syncobj = self.create_syncobj(false)?; 15 16 let sync_file = { 17 // Fake a command submission by signalling the syncobj immediately. The kernel 18 // attaches a null fence object which is always signalled. Other than this, there 19 // isn't a good way to create and signal a fence object from user-mode, so an actual 20 // device is required to test this properly. 21 // 22 // For a real device, the syncobj handle should be passed to a command submission 23 // which is expected to set a fence to be signalled upon completion. 24 self.syncobj_signal(&[syncobj])?; 25 26 // Export fence set by previous ioctl to file descriptor. 27 self.syncobj_to_fd(syncobj, true) 28 }; 29 30 // The sync file descriptor constitutes ownership of the fence, so the syncobj can be 31 // safely destroyed. 32 self.destroy_syncobj(syncobj)?; 33 34 sync_file 35 } 36 } 37 main()38 fn main() { 39 let card = Card::open_global(); 40 let sync_file = card.simulate_command_submission().unwrap(); 41 let fd = sync_file.as_fd(); 42 43 // Poll for readability. The DRM fence object will directly wake the thread when signalled. 44 // 45 // Alternatively, Tokio's AsyncFd may be used like so: 46 // 47 // use tokio::io::{Interest, unix::AsyncFd}; 48 // let afd = AsyncFd::with_interest(sync_file, Interest::READABLE).unwrap(); 49 // let future = async move { afd.readable().await.unwrap().retain_ready() }; 50 // future.await; 51 let mut poll_fds = [rustix::event::PollFd::new(&fd, PollFlags::IN)]; 52 rustix::event::poll(&mut poll_fds, -1).unwrap(); 53 } 54