Skip to content

Commit d139c53

Browse files
committed
timer skip list try RT-Thread#1
1 parent 7bdb082 commit d139c53

File tree

3 files changed

+150
-51
lines changed

3 files changed

+150
-51
lines changed

include/rtdef.h

+10-1
Original file line numberDiff line numberDiff line change
@@ -410,14 +410,23 @@ struct rt_object_information
410410
#define RT_TIMER_CTRL_SET_ONESHOT 0x2 /**< change timer to one shot */
411411
#define RT_TIMER_CTRL_SET_PERIODIC 0x3 /**< change timer to periodic */
412412

413+
#ifndef RT_TIMER_SKIP_LIST_LEVEL
414+
#define RT_TIMER_SKIP_LIST_LEVEL 3
415+
#endif
416+
417+
/* 1 or 3 */
418+
#ifndef RT_TIMER_SKIP_LIST_MASK
419+
#define RT_TIMER_SKIP_LIST_MASK 0x3
420+
#endif
421+
413422
/**
414423
* timer structure
415424
*/
416425
struct rt_timer
417426
{
418427
struct rt_object parent; /**< inherit from rt_object */
419428

420-
rt_list_t list; /**< the node of timer list */
429+
rt_list_t row[RT_TIMER_SKIP_LIST_LEVEL];
421430

422431
void (*timeout_func)(void *parameter); /**< timeout function */
423432
void *parameter; /**< timeout function's parameter */

src/thread.c

+2-7
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,7 @@ static void rt_thread_exit(void)
6161
thread->stat = RT_THREAD_CLOSE;
6262

6363
/* remove it from timer list */
64-
rt_list_remove(&(thread->thread_timer.list));
65-
rt_object_detach((rt_object_t)&(thread->thread_timer));
64+
rt_timer_detach(&thread->thread_timer);
6665

6766
if ((rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) &&
6867
thread->cleanup == RT_NULL)
@@ -613,11 +612,7 @@ rt_err_t rt_thread_resume(rt_thread_t thread)
613612
/* remove from suspend list */
614613
rt_list_remove(&(thread->tlist));
615614

616-
/* remove thread timer */
617-
rt_list_remove(&(thread->thread_timer.list));
618-
619-
/* change timer state */
620-
thread->thread_timer.parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
615+
rt_timer_stop(&thread->thread_timer);
621616

622617
/* enable interrupt */
623618
rt_hw_interrupt_enable(temp);

src/timer.c

+138-43
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
#include <rthw.h>
3535

3636
/* hard timer list */
37-
static rt_list_t rt_timer_list = RT_LIST_OBJECT_INIT(rt_timer_list);
37+
static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
3838

3939
#ifdef RT_USING_TIMER_SOFT
4040
#ifndef RT_TIMER_THREAD_STACK_SIZE
@@ -46,7 +46,7 @@ static rt_list_t rt_timer_list = RT_LIST_OBJECT_INIT(rt_timer_list);
4646
#endif
4747

4848
/* soft timer list */
49-
static rt_list_t rt_soft_timer_list;
49+
static rt_list_t rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
5050
static struct rt_thread timer_thread;
5151
ALIGN(RT_ALIGN_SIZE)
5252
static rt_uint8_t timer_thread_stack[RT_TIMER_THREAD_STACK_SIZE];
@@ -83,6 +83,8 @@ static void _rt_timer_init(rt_timer_t timer,
8383
rt_tick_t time,
8484
rt_uint8_t flag)
8585
{
86+
int i;
87+
8688
/* set flag */
8789
timer->parent.flag = flag;
8890

@@ -96,21 +98,64 @@ static void _rt_timer_init(rt_timer_t timer,
9698
timer->init_tick = time;
9799

98100
/* initialize timer list */
99-
rt_list_init(&(timer->list));
101+
for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++)
102+
{
103+
rt_list_init(&(timer->row[i]));
104+
}
100105
}
101106

102-
static rt_tick_t rt_timer_list_next_timeout(rt_list_t *timer_list)
107+
/* the fist timer always in the last row */
108+
static rt_tick_t rt_timer_list_next_timeout(rt_list_t timer_list[])
103109
{
104110
struct rt_timer *timer;
105111

106-
if (rt_list_isempty(timer_list))
112+
if (rt_list_isempty(&timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))
107113
return RT_TICK_MAX;
108114

109-
timer = rt_list_entry(timer_list->next, struct rt_timer, list);
115+
timer = rt_list_entry(timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next,
116+
struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
110117

111118
return timer->timeout_tick;
112119
}
113120

121+
rt_inline void _rt_timer_remove(rt_timer_t timer)
122+
{
123+
int i;
124+
125+
for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++)
126+
{
127+
rt_list_remove(&timer->row[i]);
128+
}
129+
}
130+
131+
static int rt_timer_count_height(struct rt_timer *timer)
132+
{
133+
int i, cnt = 0;
134+
135+
for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++)
136+
{
137+
if (!rt_list_isempty(&timer->row[i]))
138+
cnt++;
139+
}
140+
return cnt;
141+
}
142+
143+
static void rt_timer_dump(rt_list_t timer_heads[])
144+
{
145+
rt_list_t *list;
146+
147+
for (list = timer_heads[RT_TIMER_SKIP_LIST_LEVEL-1].next;
148+
list != &timer_heads[RT_TIMER_SKIP_LIST_LEVEL-1];
149+
list = list->next)
150+
{
151+
struct rt_timer *timer = rt_list_entry(list,
152+
struct rt_timer,
153+
row[RT_TIMER_SKIP_LIST_LEVEL-1]);
154+
rt_kprintf("%d", rt_timer_count_height(timer));
155+
}
156+
rt_kprintf("\n");
157+
}
158+
114159
/**
115160
* @addtogroup Clock
116161
*/
@@ -162,8 +207,7 @@ rt_err_t rt_timer_detach(rt_timer_t timer)
162207
/* disable interrupt */
163208
level = rt_hw_interrupt_disable();
164209

165-
/* remove it from timer list */
166-
rt_list_remove(&(timer->list));
210+
_rt_timer_remove(timer);
167211

168212
/* enable interrupt */
169213
rt_hw_interrupt_enable(level);
@@ -224,8 +268,7 @@ rt_err_t rt_timer_delete(rt_timer_t timer)
224268
/* disable interrupt */
225269
level = rt_hw_interrupt_disable();
226270

227-
/* remove it from timer list */
228-
rt_list_remove(&(timer->list));
271+
_rt_timer_remove(timer);
229272

230273
/* enable interrupt */
231274
rt_hw_interrupt_enable(level);
@@ -246,9 +289,14 @@ RTM_EXPORT(rt_timer_delete);
246289
*/
247290
rt_err_t rt_timer_start(rt_timer_t timer)
248291
{
292+
int row_lvl;
249293
struct rt_timer *t;
294+
rt_list_t *timer_list;
250295
register rt_base_t level;
251-
rt_list_t *n, *timer_list;
296+
rt_list_t *row_head[RT_TIMER_SKIP_LIST_LEVEL];
297+
rt_list_t *row_head_li;
298+
static unsigned int random_nr;
299+
unsigned int tst_nr;
252300

253301
/* timer check */
254302
RT_ASSERT(timer != RT_NULL);
@@ -271,39 +319,62 @@ rt_err_t rt_timer_start(rt_timer_t timer)
271319
if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
272320
{
273321
/* insert timer to soft timer list */
274-
timer_list = &rt_soft_timer_list;
322+
timer_list = rt_soft_timer_list;
275323
}
276324
else
277325
#endif
278326
{
279327
/* insert timer to system timer list */
280-
timer_list = &rt_timer_list;
328+
timer_list = rt_timer_list;
281329
}
282330

283-
for (n = timer_list->next; n != timer_list; n = n->next)
331+
row_head_li = timer_list;
332+
for (row_lvl = 0; row_lvl < RT_TIMER_SKIP_LIST_LEVEL; row_lvl++)
284333
{
285-
t = rt_list_entry(n, struct rt_timer, list);
286-
287-
/*
288-
* It supposes that the new tick shall less than the half duration of
289-
* tick max. And if we have two timers that timeout at the same time,
290-
* it's prefered that the timer inserted early get called early.
291-
*/
292-
if ((t->timeout_tick - timer->timeout_tick) == 0)
293-
{
294-
rt_list_insert_after(n, &(timer->list));
295-
break;
296-
}
297-
else if ((t->timeout_tick - timer->timeout_tick) < RT_TICK_MAX / 2)
334+
for (row_head[row_lvl] = row_head_li[row_lvl].next;
335+
row_head[row_lvl] != timer_list[row_lvl].prev;
336+
row_head[row_lvl] = row_head[row_lvl]->next)
298337
{
299-
rt_list_insert_before(n, &(timer->list));
300-
break;
338+
rt_list_t *p = row_head[row_lvl]->next;
339+
/* fix up the entry pointer */
340+
t = rt_list_entry(p, struct rt_timer, row[row_lvl]);
341+
342+
/* If we have two timers that timeout at the same time, it's
343+
* preferred that the timer inserted early get called early.
344+
* So insert the new timer to the end the the some-timeout timer
345+
* list.
346+
*/
347+
if ((t->timeout_tick - timer->timeout_tick) == 0)
348+
{
349+
continue;
350+
}
351+
else if ((t->timeout_tick - timer->timeout_tick) < RT_TICK_MAX / 2)
352+
{
353+
row_head_li = row_head[row_lvl]-row_lvl;
354+
break;
355+
}
301356
}
302357
}
303-
/* no found suitable position in timer list */
304-
if (n == timer_list)
358+
359+
/* Interestingly, this super simple timer insert counter works very very
360+
* well on distributing the list height uniformly. By means of "very very
361+
* well", I mean it beats the randomness of timer->timeout_tick very easily
362+
* (actually, the timeout_tick is not random and easy to be attacked). */
363+
random_nr++;
364+
tst_nr = random_nr;
365+
366+
rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL-1],
367+
&(timer->row[RT_TIMER_SKIP_LIST_LEVEL-1]));
368+
for (row_lvl = 2; row_lvl <= RT_TIMER_SKIP_LIST_LEVEL; row_lvl++)
305369
{
306-
rt_list_insert_before(n, &(timer->list));
370+
if (!(tst_nr & RT_TIMER_SKIP_LIST_MASK))
371+
rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL - row_lvl],
372+
&(timer->row[RT_TIMER_SKIP_LIST_LEVEL - row_lvl]));
373+
else
374+
break;
375+
/* Shift over the bits we have tested. Works well with 1 bit and 2
376+
* bits. */
377+
tst_nr >>= (RT_TIMER_SKIP_LIST_MASK+1)>>1;
307378
}
308379

309380
timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED;
@@ -349,8 +420,7 @@ rt_err_t rt_timer_stop(rt_timer_t timer)
349420
/* disable interrupt */
350421
level = rt_hw_interrupt_disable();
351422

352-
/* remove it from timer list */
353-
rt_list_remove(&(timer->list));
423+
_rt_timer_remove(timer);
354424

355425
/* enable interrupt */
356426
rt_hw_interrupt_enable(level);
@@ -410,6 +480,7 @@ void rt_timer_check(void)
410480
struct rt_timer *t;
411481
rt_tick_t current_tick;
412482
register rt_base_t level;
483+
/*int dumped = 0;*/
413484

414485
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check enter\n"));
415486

@@ -418,20 +489,30 @@ void rt_timer_check(void)
418489
/* disable interrupt */
419490
level = rt_hw_interrupt_disable();
420491

421-
while (!rt_list_isempty(&rt_timer_list))
492+
while (!rt_list_isempty(&rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL-1]))
422493
{
423-
t = rt_list_entry(rt_timer_list.next, struct rt_timer, list);
494+
t = rt_list_entry(rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next,
495+
struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
424496

425497
/*
426498
* It supposes that the new tick shall less than the half duration of
427499
* tick max.
428500
*/
429501
if ((current_tick - t->timeout_tick) < RT_TICK_MAX/2)
430502
{
503+
/*
504+
*if (!dumped)
505+
*{
506+
* dumped = 1;
507+
* [>rt_kprintf("%s:\n", __FUNCTION__);<]
508+
* rt_timer_dump(rt_timer_list);
509+
*}
510+
*/
511+
431512
RT_OBJECT_HOOK_CALL(rt_timer_timeout_hook, (t));
432513

433514
/* remove timer from timer list firstly */
434-
rt_list_remove(&(t->list));
515+
_rt_timer_remove(t);
435516

436517
/* call timeout function */
437518
t->timeout_func(t->parameter);
@@ -471,7 +552,7 @@ void rt_timer_check(void)
471552
*/
472553
rt_tick_t rt_timer_next_timeout_tick(void)
473554
{
474-
return rt_timer_list_next_timeout(&rt_timer_list);
555+
return rt_timer_list_next_timeout(rt_timer_list);
475556
}
476557

477558
#ifdef RT_USING_TIMER_SOFT
@@ -489,9 +570,10 @@ void rt_soft_timer_check(void)
489570

490571
current_tick = rt_tick_get();
491572

492-
for (n = rt_soft_timer_list.next; n != &(rt_soft_timer_list);)
573+
for (n = rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL-1].next;
574+
n != &(rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL-1]);)
493575
{
494-
t = rt_list_entry(n, struct rt_timer, list);
576+
t = rt_list_entry(n, struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL-1]);
495577

496578
/*
497579
* It supposes that the new tick shall less than the half duration of
@@ -505,7 +587,7 @@ void rt_soft_timer_check(void)
505587
n = n->next;
506588

507589
/* remove timer from timer list firstly */
508-
rt_list_remove(&(t->list));
590+
_rt_timer_remove(timer);
509591

510592
/* call timeout function */
511593
t->timeout_func(t->parameter);
@@ -542,7 +624,7 @@ static void rt_thread_timer_entry(void *parameter)
542624
while (1)
543625
{
544626
/* get the next timeout tick */
545-
next_timeout = rt_timer_list_next_timeout(&rt_soft_timer_list);
627+
next_timeout = rt_timer_list_next_timeout(rt_soft_timer_list);
546628
if (next_timeout == RT_TICK_MAX)
547629
{
548630
/* no software timer exist, suspend self. */
@@ -584,6 +666,12 @@ static void rt_thread_timer_entry(void *parameter)
584666
*/
585667
void rt_system_timer_init(void)
586668
{
669+
int i;
670+
671+
for (i = 0; i < sizeof(rt_timer_list)/sizeof(rt_timer_list[0]); i++)
672+
{
673+
rt_list_init(rt_timer_list+i);
674+
}
587675
}
588676

589677
/**
@@ -594,7 +682,14 @@ void rt_system_timer_init(void)
594682
void rt_system_timer_thread_init(void)
595683
{
596684
#ifdef RT_USING_TIMER_SOFT
597-
rt_list_init(&rt_soft_timer_list);
685+
int i;
686+
687+
for (i = 0;
688+
i < sizeof(rt_soft_timer_list)/sizeof(rt_soft_timer_list[0]);
689+
i++)
690+
{
691+
rt_list_init(rt_soft_timer_list+i);
692+
}
598693

599694
/* start software timer thread */
600695
rt_thread_init(&timer_thread,

0 commit comments

Comments
 (0)