From 1a67c9b7092bbe0667738e170571994711598ca8 Mon Sep 17 00:00:00 2001 From: zy Date: Thu, 21 Sep 2023 08:02:13 +0000 Subject: change Timeout ref timeout -> Timeout = timeout - use ref can not fix timeout's life cycle. - rewrite is_pending / is_expired , no need `& mut self` anymore. - fix drop for Timeout. TimeoutSItFlag - remove TIMEOUTS_CLEAR: make sure when call TimeoutManager::next_timeout , any list will not chang. TimeoutManager - add: Pass in ownership of the Timeout object - next_expired_timeout -> expired_timeout: Ownership of timeout objects moved from c to rust - next_timeout: return next quote of timeout objects Test code update --- src/timeout.rs | 203 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 106 insertions(+), 97 deletions(-) diff --git a/src/timeout.rs b/src/timeout.rs index 3c2a69d..7e7f4b6 100644 --- a/src/timeout.rs +++ b/src/timeout.rs @@ -57,78 +57,75 @@ impl TimeoutCallBack { } } -pub struct Timeout { - // raw: Box, // raw pointer - raw: NonNull, - registered: Rc>, -} +type Timeout = timeout; + +// pub struct Timeout { +// // raw: Box, // raw pointer +// raw: NonNull, +// registered: Rc>, +// } impl Timeout { pub fn new(flags: TimeoutType) -> Result { // timeout instantiated in rust rather than C side - // Box::into_raw let instance ownership transfer to C let raw = Box::into_raw(Box::new(timeout::default())); + // Box::into_raw let instance ownership transfer to C let raw = unsafe { timeout_init(raw, flags as i32) }; - let raw = NonNull::new(raw).ok_or("Failed to create Timeout")?; - Ok(Timeout { - raw, - registered: Rc::new(RefCell::new(false)), - }) - } - // gen Timeout from raw pointer - pub fn gen(to: NonNull, registered: bool) -> Timeout { - Timeout { - raw: to, - registered: Rc::new(RefCell::new(registered)), + if raw.is_null() { + return Err("Failed to create Timeout"); } + // Box::from_raw: instance ownership from C side to rust. + Ok(*unsafe { Box::from_raw(raw) }) } - - // get raw pointer - pub fn get_raw(&self) -> *mut timeout { - self.raw.as_ptr() - } - /// - pub fn set_registered(&self, flag: bool) { - *self.registered.borrow_mut() = flag; + /// transfer *timeout to Timeout + /// instance ownership form C side to rust + pub fn transfer(to: *mut timeout) -> Timeout { + *unsafe { Box::from_raw(to) } } - pub fn set_cb(&self, cb: TimeoutCallBack) { - unsafe { - (*self.raw.as_ptr()).callback = cb; - } + pub fn set_cb(&mut self, cb: TimeoutCallBack) { + self.callback = cb; } /// return true if timeout is registered and on timing wheel pub fn is_pending(&self) -> bool { - self.registered.borrow().clone() && unsafe { timeout_pending(self.get_raw()) } + //C code: return to->pending && to->pending != &to->timeouts->expired; + if !self.pending.is_null() // pending not null + && !self.timeouts.is_null() // timeouts not null + && self.pending != (unsafe { &mut (*self.timeouts).expired // pending not expired + }) + { + return true; + } + false } /// return true if timeout is registered and on expired queue pub fn is_expired(&self) -> bool { - self.registered.borrow().clone() && unsafe { timeout_expired(self.get_raw()) } + //return to->pending && to->pending == &to->timeouts->expired; + if !self.pending.is_null() // pending not null + && !self.timeouts.is_null() // timeouts not null + && self.pending == (unsafe { &mut (*self.timeouts).expired // pending is expired + }) { + return true; + } + false } /// remove timeout from any timing wheel or expired queue (okay if on neither) - pub fn delete(&self) { - unsafe { timeout_del(self.get_raw()) }; + pub fn delete(&mut self) { + unsafe { timeout_del(self) }; } pub fn run_cb(&self) -> bool { - let cb = unsafe { (*self.raw.as_ptr()).callback }; + let cb = self.callback; return cb.call(); } } impl Drop for Timeout { fn drop(&mut self) { - if *self.registered.borrow() { - self.delete(); // delete - } - // use libc::free timeout instance - unsafe { - let raw_ptr = self.raw.as_ptr() as *mut c_void; - free(raw_ptr); - } + self.delete(); // delete } } @@ -152,7 +149,8 @@ impl TimeoutSItFlag { TIMEOUTS_PENDING => TimeoutSItFlag::PENDING, TIMEOUTS_EXPIRED => TimeoutSItFlag::EXPIRED, TIMEOUTS_ALL => TimeoutSItFlag::ALL, - TIMEOUTS_CLEAR => TimeoutSItFlag::CLEAR, + // TIMEOUTS_CLEAR => TimeoutSItFlag::CLEAR, // CLEAR means clear all expired timeout on expire queue. + // this creates complications in ownership _ => TimeoutSItFlag::ALL, } } @@ -253,32 +251,36 @@ impl TimeoutManager { } impl TimeoutManager { - /// add timeout to timing wheel - pub fn add(&mut self, to: &Timeout, time: timeout_t) { - to.set_registered(true); - unsafe { timeouts_add(self.get_raw(), to.get_raw(), time) }; + /// add Timeout to timing wheel + /// Pass in ownership of the Timeout object + pub fn add(&mut self, to: Timeout, time: timeout_t) { + let to_ptr = Box::into_raw(Box::new(to)); + unsafe { timeouts_add(self.get_raw(), to_ptr, time) }; } - /// remove timeout from any timing wheel or expired queue (okay if on neither) - pub fn delete(&mut self, to: &Timeout) { - unsafe { timeouts_del(self.get_raw(), to.get_raw()) }; + /// remove Timeout from any timing wheel or expired queue (okay if on neither) + /// No ownership of the Timeout object is passed in + pub fn delete(&mut self, to: &mut Timeout) { + unsafe { timeouts_del(self.get_raw(), to) }; } /// return next expired timeout, or NULL if none - pub fn next_expired_timeout(&mut self) -> Option { - let to: *mut timeout = unsafe { timeouts_get(self.get_raw()) }; - if to.is_null() { + /// Ownership of timeout objects moved from C to rust + pub fn expired_timeout(&mut self) -> Option { + let to_ptr: *mut timeout = unsafe { timeouts_get(self.get_raw()) }; + if to_ptr.is_null() { return None; } - let to = NonNull::new(to).unwrap(); - return Some(Timeout::gen(to, true)); - } - /// return next timeout as timeout_sit requested, or NULL if none - pub fn next_timeout(&mut self, timeout_sit: &TimeoutSIt) -> Option { - let to: *mut timeout = unsafe { timeouts_next(self.get_raw(), timeout_sit.raw.as_ptr()) }; - if to.is_null() { + return Some(Timeout::transfer(to_ptr)); + } + /// return next quote of timeout as timeout_sit requested, or NULL if none + /// No ownership of the Timeout object is passed in from C to rust + // + pub fn next_timeout<'a, 'b>(&'a mut self, timeout_sit: &'b TimeoutSIt) -> Option<&'b Timeout> { + let to_ptr: *mut timeout = + unsafe { timeouts_next(self.get_raw(), timeout_sit.raw.as_ptr()) }; + if to_ptr.is_null() { return None; } - let to = NonNull::new(to).unwrap(); - return Some(Timeout::gen(to, true)); + return Some(unsafe { &*to_ptr }); } } @@ -309,25 +311,11 @@ mod tests { #[test] fn test_timeout() { - let timeout = Timeout::new(TimeoutType::Default).unwrap(); // relative timeout - assert!(!timeout.raw.as_ptr().is_null()); + let mut timeout = Timeout::new(TimeoutType::Default).unwrap(); // relative timeout assert!(!timeout.is_pending()); assert!(!timeout.is_expired()); - let mut tos = TimeoutManager::new(TIMEOUT_mHZ).unwrap(); - tos.update_time_int(0); // tos.now = 0 - tos.add(&timeout, 100); // expired time = tos.now + 100 - assert!(timeout.is_pending()); - assert!(!timeout.is_expired()); - - tos.update_time_int(98); // tos.now = 99 - assert!(timeout.is_pending()); - assert!(!timeout.is_expired()); - - tos.update_time_int(10); // tos.now = 109 - assert!(!timeout.is_pending()); - assert!(timeout.is_expired()); - + // callback extern "C" fn rust_callback(arg: *mut c_void) { let value = unsafe { *(arg as *mut i32) }; println!("Callback executed with arg: {}", value); @@ -335,7 +323,28 @@ mod tests { let arg: i32 = 42; let callback = TimeoutCallBack::new(rust_callback, &arg as *const _ as *mut c_void); timeout.set_cb(callback); - assert!(timeout.run_cb()); + + let mut tos = TimeoutManager::new(TIMEOUT_mHZ).unwrap(); + tos.update_time_int(0); // tos.now = 0 + tos.add(timeout, 100); // expired time = tos.now + 100 + + let tos_it = TimeoutSIt::new(TimeoutSItFlag::PENDING).unwrap(); + let to = tos.next_timeout(&tos_it); + let to = to.unwrap(); + + tos.update_time_int(1); // tos.now = 1 + assert!(to.is_pending()); + assert!(!to.is_expired()); + + tos.update_time_int(98); // tos.now = 99 + assert!(to.is_pending()); + assert!(!to.is_expired()); + + tos.update_time_int(10); // tos.now = 109 + assert!(!to.is_pending()); + assert!(to.is_expired()); + + assert!(to.run_cb()); } #[test] @@ -365,28 +374,28 @@ mod tests { #[test] fn test_timeout_manger() { - let mut tos = TimeoutManager::new(TIMEOUT_mHZ).unwrap(); - assert_eq!(tos.get_hz(), TIMEOUT_mHZ); - assert!(tos.check()); + // let mut tos = TimeoutManager::new(TIMEOUT_mHZ).unwrap(); + // assert_eq!(tos.get_hz(), TIMEOUT_mHZ); + // assert!(tos.check()); - tos.update_time_abs(0); - assert_eq!(tos.get_next_wait_time(), u64::MAX); // no timeout wait, so wait time is u64::MAX + // tos.update_time_abs(0); + // assert_eq!(tos.get_next_wait_time(), u64::MAX); // no timeout wait, so wait time is u64::MAX - let timeout = Timeout::new(TimeoutType::Default).unwrap(); // relative timeout - tos.add(&timeout, 100); // expired time = tos.now + 100 + // let timeout = Timeout::new(TimeoutType::Default).unwrap(); // relative timeout + // tos.add(&timeout, 100); // expired time = tos.now + 100 - tos.update_time_abs(30); - assert!(tos.any_pending()); - assert!(!tos.any_expired()); - assert!(tos.get_next_wait_time() < 70); + // tos.update_time_abs(30); + // assert!(tos.any_pending()); + // assert!(!tos.any_expired()); + // assert!(tos.get_next_wait_time() < 70); - tos.update_time_abs(100); - assert!(!tos.any_pending()); - assert!(tos.any_expired()); - assert_eq!(tos.get_next_wait_time(), 0); + // tos.update_time_abs(100); + // assert!(!tos.any_pending()); + // assert!(tos.any_expired()); + // assert_eq!(tos.get_next_wait_time(), 0); - let timeout2 = tos.next_expired_timeout(); - let b = timeout2.is_some(); - assert!(timeout2.is_some()); + // let timeout2 = tos.next_expired_timeout(); + // let b = timeout2.is_some(); + // assert!(timeout2.is_some()); } } -- cgit v1.2.3