summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/timeout.rs191
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());
+ }
+}