rust_rsm/rsm/
rsm_timer.rs

1#![allow(non_camel_case_types)]
2#![allow(non_snake_case)]
3#![allow(non_upper_case_globals)]
4#![allow(dead_code)]
5
6///rsm timer manager
7/// Application call set_timer to activate a timer for specific duration and loop_count, and get rsm_timer_id_t 
8/// set_timer(dur_msec:u64,loop_count:u64,timer_data:usize)->Option<rsm_timer_id_t>
9/// later application can kill the timer by invoke kill_timer_by_id
10/// Once the timer is set, application can get a timer event on the Runnable Trait called by RSM
11/// 
12
13use super::*;
14use crate::common::{self,errcode,tsidallocator::TsIdAllocator,tsmap::TsHashMap};
15use os_timer;
16const MAX_TIMER_COUNT:usize = 192*1024;
17const MAX_TIMER_PER_CAT:usize = 64*1024;
18const INVALID_TIMER_ID:rsm_timer_id_t = TsIdAllocator::INVALID_ID;
19
20const TIMER_CAT_10MS:u8=1;
21const TIMER_CAT_100MS:u8=2;
22const TIMER_CAT_1S:u8=3;
23
24#[derive(Clone,Default)]
25pub struct timer_stats_t {
26    total:usize,
27    timer_count_10ms:usize,
28    timer_count_100ms:usize,
29    timer_count_1s:usize,
30}
31
32struct timer_desc_t {
33    id:rsm_timer_id_t,
34    duration_msec:u64,
35    loop_count:u64,
36    timer_data:usize,
37    last_fired:u64,
38    expired_count:u64,
39    cid:rsm_component_t,
40}
41
42type timer_hash_map = TsHashMap<rsm_timer_id_t,timer_desc_t>;
43static mut gTimerIdAlloc:Option<TsIdAllocator>=None;
44static mut gTimerCatMap:[u8;MAX_TIMER_COUNT+1]=[0;MAX_TIMER_COUNT+1];
45static mut gTimer10ms:Option<timer_hash_map>=None;
46static mut gTimer100ms:Option<timer_hash_map>=None;
47static mut gTimer1s:Option<timer_hash_map>=None;
48
49///initialize timer
50pub(crate) fn init_timer() {
51    unsafe {
52        if gTimerIdAlloc.is_some() {
53            return
54        }
55        gTimerIdAlloc = Some(TsIdAllocator::new(1, MAX_TIMER_COUNT as i32));
56        gTimer10ms = Some(TsHashMap::new(MAX_TIMER_PER_CAT));
57        gTimer100ms = Some(TsHashMap::new(MAX_TIMER_PER_CAT));
58        gTimer1s = Some(TsHashMap::new(MAX_TIMER_PER_CAT));
59    }
60
61    println!("RSM Init Timer finished");
62}
63
64fn get_timer_cb_by_duration(dur_msec:u64)->Option<&'static mut timer_hash_map> {
65    if dur_msec<100 {
66        return unsafe {(&mut gTimer10ms).as_mut()}
67    } else if dur_msec<1000{
68        return unsafe {(&mut gTimer100ms).as_mut()}
69    }
70    return unsafe {(&mut gTimer1s).as_mut()}
71}
72
73fn get_timer_cb_by_cat(timer_cat:u8)->Option<&'static mut timer_hash_map> {
74    match timer_cat {
75        TIMER_CAT_10MS=> return unsafe {(&mut gTimer10ms).as_mut()},
76        TIMER_CAT_100MS=> return unsafe {(&mut gTimer100ms).as_mut()},
77        TIMER_CAT_1S=> return unsafe {(&mut gTimer1s).as_mut()},
78        _=>None, 
79    }    
80}
81
82fn get_timer_cat(dur_msec:u64)->u8 {
83    if dur_msec<100 {
84        return TIMER_CAT_10MS
85    } else if dur_msec<1000{
86        return TIMER_CAT_100MS
87    }
88    return TIMER_CAT_1S 
89}
90
91fn set_timer_cat_map(id:rsm_timer_id_t,cat:u8)->errcode::RESULT {
92    if cat<TIMER_CAT_10MS || cat>TIMER_CAT_1S || id as usize>MAX_TIMER_COUNT{
93        return errcode::ERROR_INVALID_PARAM
94    }
95    unsafe {
96        gTimerCatMap[id as usize] = cat;
97    }
98
99    errcode::RESULT_SUCCESS
100}
101///set a timer, loop_count=1 indicate a one time timer, 0-loop forever
102pub fn set_timer(dur_msec:u64,loop_count:u64,timer_data:usize)->Option<rsm_timer_id_t> {
103    let ida = match unsafe { &mut gTimerIdAlloc} {
104        None=>return None,
105        Some(a)=> a,
106    };
107    let id = ida.allocate_id();
108    if id==INVALID_TIMER_ID {
109        return None;
110    }
111    let caller = match rsm_sched::get_self_cid() {
112        None=>return None,
113        Some(c)=>c,
114    };
115    let timer = timer_desc_t {
116        id:id,
117        duration_msec:dur_msec,
118        loop_count:loop_count,
119        timer_data:timer_data,
120        last_fired:get_inner_time_stamp(),
121        cid:caller,
122        expired_count:0,
123    };
124
125    let timer_cat = get_timer_cat(dur_msec);
126    let timer_map = match get_timer_cb_by_cat(timer_cat) {
127        None=>return None,
128        Some(m)=>m,
129    };
130    if timer_map.insert(id,timer)!=errcode::RESULT_SUCCESS {
131        ida.release_id(id);
132        return None        
133    }
134    set_timer_cat_map(id, timer_cat);
135    return Some(id)
136}
137
138pub fn kill_timer_by_id(timer_id:rsm_timer_id_t)->errcode::RESULT {
139    if timer_id as usize> MAX_TIMER_COUNT {
140        return errcode::ERROR_INVALID_PARAM
141    }
142
143    let cid=match rsm_sched::get_self_cid() {
144        None=>return errcode::ERROR_INVALID_STATE,
145        Some(c)=>c,
146    };
147    let cat = unsafe {gTimerCatMap[timer_id as usize]};
148    let pMap = match get_timer_cb_by_cat(cat) {
149        None=>return errcode::ERROR_NOT_FOUND,
150        Some(m)=>m
151    };
152    
153    if let Some(timer) = pMap.get(&timer_id) {
154        if timer.cid !=cid {
155            return errcode::ERROR_INVALID_STATE;
156        }
157    } else {
158        return errcode::ERROR_NOT_FOUND
159    }
160    pMap.remove(&timer_id);
161
162    match unsafe { &mut gTimerIdAlloc} {
163        None=>(),
164        Some(a)=>{
165            a.release_id(timer_id);
166        },
167    }
168    errcode::RESULT_SUCCESS
169}
170
171///run timer schedule task,scan the allocated timer map, send message to correspondant task
172pub(crate) fn start_timer_thread() {
173
174     init_timer();
175   
176    std::thread::spawn(move || {
177        timer_loop()
178    });
179}
180static mut cur_time_stamp:u64=0;
181fn incr_inner_time_stamp() {
182    //most os use ticks as min timer unit
183    unsafe {
184        cur_time_stamp=common::get_now_usec64()/1000;
185    }
186}
187
188fn get_inner_time_stamp()->u64 {
189    unsafe {
190        return cur_time_stamp;
191    }
192}
193
194const TIMER_TASK_INNER:usize = 1;
195const TIMER_TASK_10MS:usize = 2;
196const TIMER_TASK_100MS:usize = 3;
197const TIMER_TASK_1S:usize = 4;
198fn timer_loop() {
199    os_timer::init_os_timer();
200    let _tm = match os_timer::os_timer_t::new(10,TIMER_TASK_10MS,scan_timer_call_back) {
201        None=> {
202            println!("set time failed");
203            return
204        },
205        Some(t)=>t,
206    };
207    
208    loop {
209       std::thread::sleep(std::time::Duration::from_millis(1000));       
210    }
211}
212
213///send timer message
214fn send_timer_msg(cid:&rsm_component_t,tid:rsm_timer_id_t,timer_data:usize) {
215    let timer_msg = match rsm_message_t::new_timer_msg(tid, timer_data) {
216        None=>return,
217        Some(m)=>m,
218    };
219    rsm_sched::send_asyn_priority_msg(cid, timer_msg);
220}
221
222///os timer callback
223fn scan_timer_call_back(_timerId:i32,timer_data:usize) {
224    static mut count:u64=0;
225    match timer_data {
226        //TIMER_TASK_INNER=>incr_inner_time_stamp(),
227        TIMER_TASK_10MS=> {
228            unsafe { count+=1;};
229            incr_inner_time_stamp();
230            scan_timer_10ms();
231            if unsafe { count % 10==0} {
232                scan_timer_100ms();
233            }
234            if unsafe { count % 100==0 } {
235                scan_timer_1s();
236            }
237            
238        },
239        _=>(),
240    }
241}
242///scan 10ms timer, and send timer message to specific component
243fn scan_timer_10ms() {
244    let tMap = match unsafe { &mut gTimer10ms} {
245        None=>return,
246        Some(m)=>m,
247    };
248    scan_timer_proc(tMap);
249}
250
251fn scan_timer_100ms() {
252    let tMap = match unsafe { &mut gTimer100ms} {
253        None=>return,
254        Some(m)=>m,
255    };
256    scan_timer_proc(tMap);   
257}
258
259fn scan_timer_1s() {
260    let tMap = match unsafe { &mut gTimer1s} {
261        None=>return,
262        Some(m)=>m,
263    };
264    scan_timer_proc(tMap);   
265}
266
267fn scan_timer_proc(timer_map:&mut timer_hash_map) {
268    let cur = get_inner_time_stamp();//common::get_now_usec64();
269    let mut to_delete=Vec::new();
270    for (id,t) in timer_map.iter_mut() {
271        if cur>=t.last_fired+t.duration_msec {
272            send_timer_msg(&t.cid, *id, t.timer_data);
273            t.last_fired=cur;
274            t.expired_count+=1;
275            if t.loop_count>0 && t.expired_count>=t.loop_count {
276                to_delete.push(t.id);
277            }
278            
279        }
280    }
281    timer_map.end_iter();
282    // if expiry count large than expected, remove the timer
283    for i in to_delete {
284        timer_map.remove(&i);
285    }
286}
287
288pub fn get_timer_stats()->timer_stats_t {
289    let mut stats = timer_stats_t::default();
290    unsafe {
291        stats.total =  match &gTimerIdAlloc {
292            None=>0,
293            Some(ids)=>ids.used_count() as usize,
294        };
295
296        stats.timer_count_10ms = match &gTimer10ms {
297            None=>0,
298            Some(tm)=>tm.len(),
299        };
300
301        stats.timer_count_100ms = match &gTimer100ms {
302            None=>0,
303            Some(tm)=>tm.len(),
304        };
305        stats.timer_count_1s = match &gTimer1s {
306            None=>0,
307            Some(tm)=>tm.len(),
308        };
309    }
310    
311
312    return stats
313}