[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [RFC 07/13] rust: add bindings for timer
From: |
Zhao Liu |
Subject: |
Re: [RFC 07/13] rust: add bindings for timer |
Date: |
Tue, 14 Jan 2025 23:42:07 +0800 |
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.liu@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
>
>
>