diff options
| author | zy <[email protected]> | 2023-09-20 08:11:20 +0000 |
|---|---|---|
| committer | zy <[email protected]> | 2023-09-20 08:11:20 +0000 |
| commit | 5fad62b7f916f14556a264e4d065cf57ebeb90af (patch) | |
| tree | a09a900bcc297afd702150b27ac3c9863ee3bb77 | |
| parent | fb34143a7295a57341a5111b5c61f11b7ba5950f (diff) | |
fix err
- timeout 申请内存在 rust 通过 Box::into_raw 将所有权交给 C 侧. 最后 Timeout drop 时 调用 C free释放
- 主要为了 is_pending is_expired 等方法减少样板代码
- 修正 NonNull 错误
- 简化 TimeoutType
- timeout_type timeout 的单元测试 通过
| -rw-r--r-- | src/timeout.rs | 191 |
1 files changed, 136 insertions, 55 deletions
diff --git a/src/timeout.rs b/src/timeout.rs index 97d5354..ae04060 100644 --- a/src/timeout.rs +++ b/src/timeout.rs @@ -1,27 +1,30 @@ use std::{ + cell::RefCell, ffi::c_int, + marker::PhantomData, ptr::NonNull, + rc::Rc, time::{Duration, Instant}, }; +use libc::free; + use crate::timeout_bind::*; -/// timeout flag: 使用相对时间 or 绝对时间 +/// timeout flag: relative time or absolute time, default relative time +#[derive(Debug, Clone, Copy, PartialEq)] pub enum TimeoutType { - INT, // 相对时间 - ABS, // 绝对时间 - Default, // 相对时间 + INT = TIMEOUT_INT as isize, // relative time + ABS = TIMEOUT_ABS as isize, // absolute time + Default = TIMEOUT_DEFAULT as isize, // relative time } -// 实现 as i32 +// as i32 impl From<TimeoutType> for i32 { fn from(timeout_type: TimeoutType) -> Self { - match timeout_type { - TimeoutType::INT => TIMEOUT_INT, - TimeoutType::ABS => TIMEOUT_ABS, - TimeoutType::Default => TIMEOUT_DEFAULT, - } + timeout_type as i32 } } + impl TimeoutType { // i32 -> TimeoutType fn new(flag: i32) -> Self { @@ -34,43 +37,66 @@ impl TimeoutType { } pub struct Timeout { - raw: NonNull<*mut timeout>, // timeout 是裸指针而不是实例, c 负责释放实例 + // raw: Box<timeout>, // raw pointer + raw: NonNull<timeout>, + registered: Rc<RefCell<bool>>, } impl Timeout { pub fn new(flags: TimeoutType) -> Result<Timeout, &'static str> { - let mut instance = timeout::default(); - let raw = unsafe { timeout_init(&mut instance, flags as i32) }; - let raw = NonNull::new(raw as *mut _).ok_or("Failed to create timeout")?; - Ok(Timeout { raw }) + // 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())); + 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<timeout>, registered: bool) -> Timeout { + Timeout { + raw: to, + registered: Rc::new(RefCell::new(registered)), + } + } + + // get raw pointer + pub fn get_raw(&self) -> *mut timeout { + self.raw.as_ptr() } - pub fn gen(to: NonNull<*mut timeout>) -> Timeout { - Timeout { raw: to } + /// + pub fn set_registered(&self, flag: bool) { + *self.registered.borrow_mut() = flag; } - // 检查是否在 timing wheel 上 + /// return true if timeout is registered and on timing wheel pub fn is_pending(&self) -> bool { - unsafe { timeout_pending(self.raw.as_ref().clone()) } + self.registered.borrow().clone() && unsafe { timeout_pending(self.get_raw()) } } - // 检查是否在 expired 队列上 + /// return true if timeout is registered and on expired queue pub fn is_expired(&self) -> bool { - unsafe { timeout_expired(self.raw.as_ref().clone()) } + self.registered.borrow().clone() && unsafe { timeout_expired(self.get_raw()) } } - // 从 timing wheel 上移除 + /// remove timeout from any timing wheel or expired queue (okay if on neither) pub fn delete(&self) { - unsafe { timeout_del(self.raw.as_ref().clone()) }; - } - pub fn get_type(&self) -> TimeoutType { - let flags = unsafe { (*(*self.raw.as_ptr())).flags }; - return TimeoutType::new(flags); + unsafe { timeout_del(self.get_raw()) }; } } impl Drop for Timeout { fn drop(&mut self) { - self.delete(); // drop 时候先 delete + if *self.registered.borrow() { + self.delete(); // delete + } + // use libc::free timeout instance + unsafe { + let raw_ptr = self.raw.as_ptr() as *mut std::ffi::c_void; + free(raw_ptr); + } } } @@ -80,7 +106,7 @@ pub enum TimeoutSItFlag { ALL, CLEAR, } -// 实现 as i32 +// as i32 impl From<TimeoutSItFlag> for i32 { fn from(flag: TimeoutSItFlag) -> Self { match flag { @@ -109,7 +135,7 @@ impl TimeoutSIt { // TimeoutManager pub struct TimeoutManager { - tos: NonNull<*mut timeouts>, + tos: NonNull<timeouts>, } impl TimeoutManager { @@ -121,81 +147,94 @@ impl TimeoutManager { if err != 0 { return Err("Failed to create timeout manager, null"); } - let tos = NonNull::new(tos as *mut _).ok_or("Failed to create timeout manager, null")?; + let tos = NonNull::new(tos).ok_or("Failed to create timeout manager, null")?; Ok(TimeoutManager { tos }) } + // get raw pointer + fn get_raw(&self) -> *mut timeouts { + self.tos.as_ptr() + } + // close pub fn close(&mut self) { unsafe { - timeouts_close(self.tos.as_ref().clone()); + timeouts_close(self.get_raw()); } } fn update_time(&mut self, time: timeout_t, timeout_type: TimeoutType) { + let tmp = self.get_raw(); match timeout_type { - TimeoutType::INT => unsafe { timeouts_step(self.tos.as_ref().clone(), time) }, - TimeoutType::ABS => unsafe { timeouts_update(self.tos.as_ref().clone(), time) }, - TimeoutType::Default => unsafe { timeouts_step(self.tos.as_ref().clone(), time) }, + TimeoutType::INT => unsafe { timeouts_step(self.get_raw(), time) }, + TimeoutType::ABS => unsafe { timeouts_update(self.get_raw(), time) }, + TimeoutType::Default => unsafe { timeouts_step(self.get_raw(), time) }, } } /// update time: relative time - pub fn update_time_int(&mut self, current_time: timeout_t) { - self.update_time(current_time, TimeoutType::INT); + pub fn update_time_int(&mut self, time: timeout_t) { + self.update_time(time, TimeoutType::INT); } /// update time: absolute time - pub fn update_time_abs(&mut self, time: timeout_t) { - self.update_time(time, TimeoutType::ABS); + pub fn update_time_abs(&mut self, current_time: timeout_t) { + self.update_time(current_time, TimeoutType::ABS); } /// get tos hz pub fn get_hz(&self) -> timeout_t { - unsafe { timeouts_hz(self.tos.as_ref().clone()) } + unsafe { timeouts_hz(self.get_raw()) } } /// return interval to next required update pub fn get_next_wait_time(&mut self) -> timeout_t { - unsafe { timeouts_timeout(self.tos.as_ref().clone()) } + let t = unsafe { timeouts_timeout(self.get_raw()) }; + // timeouts_timeout 取到一定程度会返回 u64 最大值 + if t == u64::MAX { + 0 + } else { + t + } } /// return true if any timeouts pending on timing wheel pub fn any_pending(&mut self) -> bool { - unsafe { timeouts_pending(self.tos.as_ref().clone()) } + unsafe { timeouts_pending(self.get_raw()) } } /// return true if any timeouts on expired queue pub fn any_expired(&mut self) -> bool { - unsafe { timeouts_expired(self.tos.as_ref().clone()) } + unsafe { timeouts_expired(self.get_raw()) } } // return true if TimeoutManager is effective pub fn check(&mut self) -> bool { - unsafe { timeouts_check(self.tos.as_ref().clone(), stderr) } + unsafe { timeouts_check(self.get_raw(), stderr) } } } impl TimeoutManager { /// add timeout to timing wheel - pub fn add(&mut self, to: Timeout, time: timeout_t) { - unsafe { timeouts_add(self.tos.as_ref().clone(), to.raw.as_ref().clone(), time) }; + pub fn add(&mut self, to: &Timeout, time: timeout_t) { + to.set_registered(true); + unsafe { timeouts_add(self.get_raw(), to.get_raw(), 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.tos.as_ref().clone(), to.raw.as_ref().clone()) }; + pub fn delete(&mut self, to: &Timeout) { + unsafe { timeouts_del(self.get_raw(), to.get_raw()) }; } /// return next expired timeout, or NULL if none pub fn next_expired_timeout(&mut self) -> Option<Timeout> { - let to: *mut timeout = unsafe { timeouts_get(self.tos.as_ref().clone()) }; + let to: *mut timeout = unsafe { timeouts_get(self.get_raw()) }; if to.is_null() { return None; } - let to = NonNull::new(to as *mut *mut timeout).unwrap(); - return Some(Timeout::gen(to)); + 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<Timeout> { + pub fn next_timeout(&mut self, timeout_sit: &TimeoutSIt) -> Option<Timeout> { let to: *mut timeout = - unsafe { timeouts_next(self.tos.as_ref().clone(), timeout_sit.raw.as_ref().clone()) }; + unsafe { timeouts_next(self.get_raw(), timeout_sit.raw.as_ref().clone()) }; if to.is_null() { return None; } - let to = NonNull::new(to as *mut *mut timeout).unwrap(); - return Some(Timeout::gen(to)); + let to = NonNull::new(to).unwrap(); + return Some(Timeout::gen(to, true)); } } @@ -204,3 +243,45 @@ impl Drop for TimeoutManager { self.close(); } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_timeout_type() { + let int_type = TimeoutType::INT; + let abs_type = TimeoutType::ABS; + let default_type = TimeoutType::Default; + + assert_eq!(i32::from(int_type), TIMEOUT_INT); + assert_eq!(i32::from(abs_type), TIMEOUT_ABS); + assert_eq!(i32::from(default_type), TIMEOUT_DEFAULT); + + assert_eq!(TimeoutType::new(TIMEOUT_INT), int_type); + assert_eq!(TimeoutType::new(TIMEOUT_ABS), abs_type); + assert_eq!(TimeoutType::new(123), default_type); + } + + #[test] + fn test_timeout() { + let timeout = Timeout::new(TimeoutType::Default).unwrap(); // relative timeout + assert!(!timeout.raw.as_ptr().is_null()); + 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()); + } +} |
