summaryrefslogtreecommitdiff
path: root/src/timeout.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/timeout.rs')
-rw-r--r--src/timeout.rs190
1 files changed, 149 insertions, 41 deletions
diff --git a/src/timeout.rs b/src/timeout.rs
index 99dd9c4..9ff8202 100644
--- a/src/timeout.rs
+++ b/src/timeout.rs
@@ -11,13 +11,16 @@ use libc::{c_void, free};
use crate::timeout_bind::*;
-/// timeout flag: relative time or absolute time, default relative time
-/// it could use as i32
+/// timeout type:
+/// - INT: Periodic timeout, start time only supports relative time.
+/// - ABS: Executed only once, start time is absolute time.
+/// - Default: Executed only once, start time is relative time
+/// TimeoutType could use as i32
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TimeoutType {
- INT = TIMEOUT_INT as isize, // relative time
- ABS = TIMEOUT_ABS as isize, // absolute time
- Default = TIMEOUT_DEFAULT as isize, // relative time
+ INT = TIMEOUT_INT as isize, // periodic timeout, relative time
+ ABS = TIMEOUT_ABS as isize, // onetime timeout, absolute time
+ Default = TIMEOUT_DEFAULT as isize, // onetime timeout, relative time
}
// as i32
impl From<TimeoutType> for i32 {
@@ -37,7 +40,7 @@ impl TimeoutType {
}
}
-type TimeoutCallBack = timeout_cb;
+type TimeoutCallBack = timeout_cb; // callback
impl TimeoutCallBack {
pub fn new<T>(callback: extern "C" fn(arg: *mut c_void), arg: *mut T) -> Self {
@@ -47,7 +50,7 @@ impl TimeoutCallBack {
arg: arg as *mut c_void,
}
}
-
+ /// run callback, if callback is None, return false
pub fn call(&self) -> bool {
if let Some(callback) = self.fn_ptr {
callback(self.arg);
@@ -59,12 +62,6 @@ impl TimeoutCallBack {
type Timeout = timeout;
-// pub struct Timeout {
-// // raw: Box<timeout>, // raw pointer
-// raw: NonNull<timeout>,
-// registered: Rc<RefCell<bool>>,
-// }
-
impl Timeout {
pub fn new(flags: TimeoutType) -> Result<Timeout, &'static str> {
// timeout instantiated in rust rather than C side
@@ -82,7 +79,7 @@ impl Timeout {
pub fn transfer(to: *mut timeout) -> Timeout {
*unsafe { Box::from_raw(to) }
}
-
+ /// set callback
pub fn set_cb(&mut self, cb: TimeoutCallBack) {
self.callback = cb;
}
@@ -111,6 +108,11 @@ impl Timeout {
}
false
}
+ /// return true if timeout is periodic
+ pub fn is_periodic(&self) -> bool {
+ // if ((to->flags & TIMEOUT_INT) && to->interval > 0)
+ return (self.flags & TIMEOUT_INT != 0) && (self.interval > 0);
+ }
/// remove timeout from any timing wheel or expired queue (okay if on neither)
pub fn delete(&mut self) {
@@ -161,7 +163,7 @@ pub struct TimeoutSIt {
}
impl TimeoutSIt {
- /// flag has 4 value: PENDING, EXPIRED, ALL, CLEAR
+ /// flag has 3 value: PENDING, EXPIRED, ALL
fn new(flags: TimeoutSItFlag) -> Result<TimeoutSIt, &'static str> {
let instance = Box::into_raw(Box::new(timeouts_it::default()));
TIMEOUTS_IT_INIT(instance, flags as i32);
@@ -179,6 +181,12 @@ impl Drop for TimeoutSIt {
}
}
+/// expired timeout return type
+pub enum TOR {
+ OneTime(Timeout), // instance ownership from C side to rust
+ Periodic(&'static Timeout), // instance ownership still on C side
+}
+
// TimeoutManager
pub struct TimeoutManager {
tos: NonNull<timeouts>,
@@ -251,29 +259,52 @@ impl TimeoutManager {
impl TimeoutManager {
/// add Timeout to timing wheel
+ /// Timeout type:
+ /// - INT: first expired on now + timeout, then expired at now + timeout + timeout + ...
+ /// even if it's expired,TimeoutManger will not auto renew it. must consume it use expired_timeouts.
+ /// - ABS: expired on timeout, then expired only once.
+ /// - Default: first expired on now + timeout, then expired only once.
/// Pass in ownership of the Timeout object
- pub fn add(&mut self, to: Timeout, time: timeout_t) {
+ pub fn add(&mut self, to: Timeout, timeout: timeout_t) {
let to_ptr = Box::into_raw(Box::new(to));
- unsafe { timeouts_add(self.get_raw(), to_ptr, time) };
+ unsafe { timeouts_add(self.get_raw(), to_ptr, timeout) };
}
/// 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) };
}
+
+ /// consume expired timeout
/// return next expired timeout, or NULL if none
- /// Ownership of timeout objects moved from C to rust
- pub fn expired_timeout(&mut self) -> Option<Timeout> {
+ /// TOR::OneTime: Ownership of timeout objects moved from C to rust
+ /// all pending/expired flag has cleared.
+ /// TOR::Periodic: Ownership still on C side
+ pub(crate) fn expired_timeout<'a>(&'a mut self) -> Option<TOR> {
let to_ptr: *mut timeout = unsafe { timeouts_get(self.get_raw()) };
if to_ptr.is_null() {
return None;
}
- return Some(Timeout::transfer(to_ptr));
+ if unsafe { (*to_ptr).is_periodic() } {
+ return Some(TOR::Periodic(unsafe { &*to_ptr }));
+ }
+ return Some(TOR::OneTime(Timeout::transfer(to_ptr)));
+ // return Some(Timeout::transfer(to_ptr));
+ }
+ /// return next expired timeout iterator
+ pub fn expired_timeouts(&mut self) -> ToMIterExpire {
+ ToMIterExpire {
+ timeout_manager: self,
+ }
}
/// 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
+ /// No consume any timeout
//
- pub fn next_timeout<'a, 'b>(&'a mut self, timeout_sit: &'b TimeoutSIt) -> Option<&'b Timeout> {
+ pub(crate) 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() {
@@ -281,6 +312,13 @@ impl TimeoutManager {
}
return Some(unsafe { &*to_ptr });
}
+ /// return next timeout quote iterator(as requested by timeout_sit)
+ pub fn next_timeouts<'a>(&'a mut self, timeout_sit: &'a TimeoutSIt) -> ToMIterNext<'a> {
+ ToMIterNext {
+ timeout_manager: self,
+ timeout_sit,
+ }
+ }
}
impl Drop for TimeoutManager {
@@ -289,6 +327,29 @@ impl Drop for TimeoutManager {
}
}
+pub struct ToMIterExpire<'a> {
+ timeout_manager: &'a mut TimeoutManager,
+}
+
+impl<'a> Iterator for ToMIterExpire<'a> {
+ type Item = TOR;
+ fn next(&mut self) -> Option<Self::Item> {
+ self.timeout_manager.expired_timeout()
+ }
+}
+
+pub struct ToMIterNext<'a> {
+ timeout_manager: &'a mut TimeoutManager,
+ timeout_sit: &'a TimeoutSIt,
+}
+
+impl<'a> Iterator for ToMIterNext<'a> {
+ type Item = &'a Timeout;
+ fn next(&mut self) -> Option<Self::Item> {
+ self.timeout_manager.next_timeout(self.timeout_sit)
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -310,26 +371,22 @@ mod tests {
#[test]
fn test_timeout() {
- let mut timeout = Timeout::new(TimeoutType::Default).unwrap(); // relative timeout
- assert!(!timeout.is_pending());
- assert!(!timeout.is_expired());
+ let to = Timeout::new(TimeoutType::Default).unwrap(); // relative timeout
+ assert!(!to.is_pending());
+ assert!(!to.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);
- }
- let arg: i32 = 42;
- let callback = TimeoutCallBack::new(rust_callback, &arg as *const _ as *mut c_void);
- timeout.set_cb(callback);
+ let to2 = Timeout::new(TimeoutType::INT).unwrap(); // relative timeout
+ assert!(!to2.is_pending());
+ assert!(!to2.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
+ tos.add(to, 100); // onetime, expired time = tos.now + 100
+ tos.add(to2, 100); // periodic
let tos_it = TimeoutSIt::new(TimeoutSItFlag::PENDING).unwrap();
- let to = tos.next_timeout(&tos_it);
- let to = to.unwrap();
+ let to = tos.next_timeout(&tos_it).unwrap();
+ let to2 = tos.next_timeout(&tos_it).unwrap();
tos.update_time_int(1); // tos.now = 1
assert!(to.is_pending());
@@ -340,10 +397,43 @@ mod tests {
assert!(!to.is_expired());
tos.update_time_int(10); // tos.now = 109
- assert!(!to.is_pending());
- assert!(to.is_expired());
- assert!(to.run_cb());
+ let tos_it = TimeoutSIt::new(TimeoutSItFlag::EXPIRED).unwrap();
+ for to in tos.next_timeouts(&tos_it) {
+ assert!(!to.is_pending());
+ assert!(to.is_expired());
+ }
+
+ for to in tos.expired_timeouts() {
+ match to {
+ TOR::OneTime(temp) => {
+ // all flag has cleared
+ // assert!(to.is_expired());
+ }
+ TOR::Periodic(temp) => {
+ assert!(temp.is_periodic()); // next expired time = 200
+ }
+ };
+ }
+
+ tos.update_time_int(110); // tos.now = 219
+
+ let mut temp_flag = false;
+
+ for to in tos.expired_timeouts() {
+ match to {
+ TOR::OneTime(temp) => {
+ // all flag has cleared
+ // assert!(to.is_expired());
+ }
+ TOR::Periodic(temp) => {
+ assert!(temp.is_periodic());
+ temp_flag = true;
+ }
+ };
+ }
+
+ assert!(temp_flag);
}
#[test]
@@ -419,6 +509,15 @@ mod tests {
}
}
+ // // callback
+ // extern "C" fn rust_callback(arg: *mut c_void) {
+ // let value = unsafe { *(arg as *mut i32) };
+ // println!("Callback executed with arg: {}", value);
+ // }
+ // let arg: i32 = 42;
+ // let callback = TimeoutCallBack::new(rust_callback, &arg as *const _ as *mut c_void);
+ // timeout.set_cb(callback);
+
let mut timeout = Timeout::new(TimeoutType::Default).unwrap(); // relative timeout
// callback
// extern "C" fn rust_callback(arg: *mut c_void) {
@@ -446,15 +545,23 @@ mod tests {
println!("rust_callback2 count: {}", Rc::strong_count(value));
- let value = value.borrow();
- println!("Callback executed with arg: {}", value.session_id);
+ // let value = value.borrow();
+ println!("Callback executed with arg: {}", value.borrow().session_id);
+ drop(value);
+ // println!("rust_callback2 count: {}", Rc::strong_count(value));
}
+
{
let s2 = Session {
session_id: "2123".to_string(),
};
let s2_ref = Rc::new(RefCell::new(s2));
- let arg2 = &mut s2_ref.clone();
+ // let arg3 = Rc::clone(&s2_ref);
+ // let arg2 = &mut s2_ref.clone();
+ // let arg2 = Rc::into_raw(s2_ref.clone());
+
+ let arg2 = Box::into_raw(Box::new(s2_ref.clone()));
+
// GET RFE COUNT FOROM S2
println!("s2_ref count: {}", Rc::strong_count(&s2_ref));
@@ -469,5 +576,6 @@ mod tests {
// timeout.run_cb();
println!("aaaa");
// timeout.run_cb();
+ // println!("s2_ref count: {}", Rc::strong_count(&s2_ref));
}
}