@@ -48,41 +48,6 @@ struct per_cpu_timers {
48
48
static DEFINE_CPU_DATA (struct per_cpu_timers , cpu_timers ) ;
49
49
static DEFINE_CPU_DATA (struct dev_handler_node * , timer_node ) ;
50
50
51
- static struct timer * find_expired_timer (
52
- struct per_cpu_timers * cpu_timer ,
53
- uint64_t tsc_now )
54
- {
55
- struct timer * timer = NULL , * tmp ;
56
- struct list_head * pos ;
57
-
58
- list_for_each (pos , & cpu_timer -> timer_list ) {
59
- tmp = list_entry (pos , struct timer , node );
60
- if (tmp -> fire_tsc <= tsc_now ) {
61
- timer = tmp ;
62
- break ;
63
- }
64
- }
65
-
66
- return timer ;
67
- }
68
-
69
- static struct timer * _search_nearest_timer (
70
- struct per_cpu_timers * cpu_timer )
71
- {
72
- struct timer * timer ;
73
- struct timer * target = NULL ;
74
- struct list_head * pos ;
75
-
76
- list_for_each (pos , & cpu_timer -> timer_list ) {
77
- timer = list_entry (pos , struct timer , node );
78
- if (target == NULL )
79
- target = timer ;
80
- else if (timer -> fire_tsc < target -> fire_tsc )
81
- target = timer ;
82
- }
83
-
84
- return target ;
85
- }
86
51
87
52
static void run_timer (struct timer * timer )
88
53
{
@@ -100,30 +65,64 @@ static int tsc_deadline_handler(__unused int irq, __unused void *data)
100
65
return 0 ;
101
66
}
102
67
103
- static inline void schedule_next_timer (struct per_cpu_timers * cpu_timer )
68
+ static inline void update_physical_timer (struct per_cpu_timers * cpu_timer )
104
69
{
105
- struct timer * timer ;
70
+ struct timer * timer = NULL ;
71
+
72
+ /* find the next event timer */
73
+ if (!list_empty (& cpu_timer -> timer_list )) {
74
+ timer = list_entry ((& cpu_timer -> timer_list )-> next ,
75
+ struct timer , node );
106
76
107
- timer = _search_nearest_timer (cpu_timer );
108
- if (timer ) {
109
77
/* it is okay to program a expired time */
110
78
msr_write (MSR_IA32_TSC_DEADLINE , timer -> fire_tsc );
111
79
}
112
80
}
113
81
82
+ static void __add_timer (struct per_cpu_timers * cpu_timer ,
83
+ struct timer * timer ,
84
+ bool * need_update )
85
+ {
86
+ struct list_head * pos , * prev ;
87
+ struct timer * tmp ;
88
+ uint64_t tsc = timer -> fire_tsc ;
89
+
90
+ prev = & cpu_timer -> timer_list ;
91
+ list_for_each (pos , & cpu_timer -> timer_list ) {
92
+ tmp = list_entry (pos , struct timer , node );
93
+ if (tmp -> fire_tsc < tsc )
94
+ prev = & tmp -> node ;
95
+ else
96
+ break ;
97
+ }
98
+
99
+ list_add (& timer -> node , prev );
100
+
101
+ if (need_update )
102
+ /* update the physical timer if we're on the timer_list head */
103
+ * need_update = (prev == & cpu_timer -> timer_list );
104
+ }
105
+
114
106
int add_timer (struct timer * timer )
115
107
{
116
108
struct per_cpu_timers * cpu_timer ;
117
109
int pcpu_id ;
110
+ bool need_update ;
118
111
119
112
if (timer == NULL || timer -> func == NULL || timer -> fire_tsc == 0 )
120
113
return - EINVAL ;
121
114
115
+ /* limit minimal periodic timer cycle period */
116
+ if (timer -> mode == TICK_MODE_PERIODIC )
117
+ timer -> period_in_cycle = max (timer -> period_in_cycle ,
118
+ US_TO_TICKS (MIN_TIMER_PERIOD_US ));
119
+
122
120
pcpu_id = get_cpu_id ();
123
121
cpu_timer = & per_cpu (cpu_timers , pcpu_id );
124
- list_add_tail ( & timer -> node , & cpu_timer -> timer_list );
122
+ __add_timer ( cpu_timer , timer , & need_update );
125
123
126
- schedule_next_timer (cpu_timer );
124
+ if (need_update )
125
+ update_physical_timer (cpu_timer );
127
126
128
127
TRACE_2L (TRACE_TIMER_ACTION_ADDED , timer -> fire_tsc , 0 );
129
128
return 0 ;
@@ -212,35 +211,38 @@ int timer_softirq(int pcpu_id)
212
211
{
213
212
struct per_cpu_timers * cpu_timer ;
214
213
struct timer * timer ;
215
- int max = MAX_TIMER_ACTIONS ;
214
+ struct list_head * pos , * n ;
215
+ int tries = MAX_TIMER_ACTIONS ;
216
+ uint64_t current_tsc = rdtsc ();
216
217
217
218
/* handle passed timer */
218
219
cpu_timer = & per_cpu (cpu_timers , pcpu_id );
219
220
220
221
/* This is to make sure we are not blocked due to delay inside func()
221
222
* force to exit irq handler after we serviced >31 timers
222
- * caller used to add_timer () in timer->func() , if there is a delay
223
+ * caller used to __add_timer () for periodic timer, if there is a delay
223
224
* inside func(), it will infinitely loop here, because new added timer
224
225
* already passed due to previously func()'s delay.
225
226
*/
226
- timer = find_expired_timer (cpu_timer , rdtsc ());
227
- while (timer && -- max > 0 ) {
228
- del_timer (timer );
229
-
230
- run_timer (timer );
231
-
232
- if (timer -> mode == TICK_MODE_PERIODIC ) {
233
- timer -> fire_tsc += max (timer -> period_in_cycle ,
234
- US_TO_TICKS (MIN_TIMER_PERIOD_US ));
235
- add_timer (timer );
236
- }
237
-
238
- /* search next one */
239
- timer = find_expired_timer (cpu_timer , rdtsc ());
227
+ list_for_each_safe (pos , n , & cpu_timer -> timer_list ) {
228
+ timer = list_entry (pos , struct timer , node );
229
+ /* timer expried */
230
+ if (timer -> fire_tsc <= current_tsc && -- tries > 0 ) {
231
+ del_timer (timer );
232
+
233
+ run_timer (timer );
234
+
235
+ if (timer -> mode == TICK_MODE_PERIODIC ) {
236
+ /* update periodic timer fire tsc */
237
+ timer -> fire_tsc += timer -> period_in_cycle ;
238
+ __add_timer (cpu_timer , timer , NULL );
239
+ }
240
+ } else
241
+ break ;
240
242
}
241
243
242
244
/* update nearest timer */
243
- schedule_next_timer (cpu_timer );
245
+ update_physical_timer (cpu_timer );
244
246
return 0 ;
245
247
}
246
248
0 commit comments