On Tue, Jan 14, 2025 at 11:36:48PM +0800, Zhao Liu wrote: > Date: Tue, 14 Jan 2025 23:36:48 +0800 > From: Zhao Liu <zhao1....@intel.com> > Subject: Re: [RFC 07/13] rust: add bindings for timer > > Hi Paolo, > > Thanks for your FnCall and the guidance below... > > > This gets tricky when you have more than one timer per device. With the > > right > > infrastructure we can make this something like > > > > fn timer_init_full<'a, 'b: 'a, T, F: 'b Fn(&'b T)>( > > &'a mut self, > > timer_list_group: Option<&mut QEMUTimerListGroup>, > > clk_type: QEMUClockType, > > scale: u32, > > attributes: u32, > > f: &F, > > opaque: &'b T) { > > // SAFETY: the opaque outlives the timer > > unsafe { > > timer_init_full(...) > > } > > } > > ... > > > pub struct Clock { > > id: QEMUClockType > > } > > > > impl Clock { > > pub fn get_ns() -> u64 { > > // SAFETY: cannot be created outside this module, therefore id > > // is valid > > (unsafe { qemu_clock_get_ns(self.id) }) as u64 > > } > > } > > > > pub static CLOCK_VIRTUAL: Clock = Clock { id: > > QEMUClockType::QEMU_CLOCK_VIRTUAL }; > > // etc. > > > > and then the user can do timer::CLOCK_VIRTUAL::get_ns(). > > > > ...Now I have a draft for timer binding: > > * timer binding:
Missed rust_timer_handler, which follows the good example of FnCall doc: unsafe extern "C" fn rust_timer_handler<T, F: for<'a> FnCall<(&'a T,)>>(opaque: *mut c_void) { // SAFETY: the opaque was passed as a reference to `T`. F::call((unsafe { &*(opaque.cast::<T>()) },)) } > impl QEMUTimer { > pub fn new() -> Self { > Zeroable::ZERO > } > > pub fn timer_init_full<'a, 'b: 'a, T, F>( > &'a mut self, > timer_list_group: Option<&mut QEMUTimerListGroup>, > clk_type: QEMUClockType, > scale: u32, > attributes: u32, > _f: &F, > opaque: &'b T, > ) where > F: for<'c> FnCall<(&'c T,)> + 'b, > { > let timer_cb: unsafe extern "C" fn(*mut c_void) = > rust_timer_handler::<T, F>; > > // SAFETY: the opaque outlives the timer > unsafe { > timer_init_full( > self, > if let Some(g) = timer_list_group { > g > } else { > ::core::ptr::null_mut() > }, > clk_type, > scale as c_int, > attributes as c_int, > Some(timer_cb), > opaque as *const T as *const c_void as *mut c_void, > ) > } > } > > pub fn timer_mod(&mut self, expire_time: u64) { > unsafe { timer_mod(self as *mut QEMUTimer, expire_time as i64) } > } > } > > > * use of timer binding: > > fn timer_handler(timer_cell: &BqlRefCell<HPETTimer>) { > timer_cell.borrow_mut().callback() > } > > impl HPETTimer { > ... > > fn init_timer_with_state(&mut self) { > let index = self.index; > let cb = |cell: &BqlRefCell<HPETTimer>| { > timer_handler(cell); > }; > > self.qemu_timer = Some(Box::new({ > let mut t = QEMUTimer::new(); > t.timer_init_full( > None, > CLOCK_VIRTUAL.id, > SCALE_NS, > 0, > &cb, > &self.get_state().timer[index], > ); > t > })); > } > ... > } > > --- > > Is this timer binding as you expected? Hope I am on the right track. :-) > > Thanks, > Zhao > > >