Linux-rt下卡死之hrtimer分析
日志
超时读过程分析
# define readl_poll_timeout ( addr, val, cond, delay_us, timeout_us) \
readx_poll_timeout ( readl, addr, val, cond, delay_us, timeout_us)
34 #define readx_poll_timeout ( op, addr, val, cond, sleep_us, timeout_us) \
35 ( { \
36 u64 __timeout_us = ( timeout_us) ; \
37 unsigned long __sleep_us = ( sleep_us) ; \
38 ktime_t __timeout = ktime_add_us ( ktime_get ( ) , __timeout_us) ; \
39 might_sleep_if ( ( __sleep_us) != 0 ) ; \
40 for ( ; ; ) { \
41 ( val) = op ( addr) ; \
42 if ( cond) \
43 break ; \
44 if ( __timeout_us && \
45 ktime_compare ( ktime_get ( ) , __timeout) > 0 ) { \
46 ( val) = op ( addr) ; \
47 break ; \
48 } \
49 if ( __sleep_us) \
50 usleep_range ( ( __sleep_us >> 2 ) + 1 , __sleep_us) ; \
51 } \
52 ( cond) ? 0 : - ETIMEDOUT; \
53 } )
2375 void __sched usleep_range ( unsigned long min, unsigned long max)
2376 {
2377 ktime_t exp = ktime_add_us ( ktime_get ( ) , min) ;
2378 u64 delta = ( u64) ( max - min) * NSEC_PER_USEC;
2379
2380 for ( ; ; ) {
2381 __set_current_state ( TASK_UNINTERRUPTIBLE) ;
2382
2383 if ( ! schedule_hrtimeout_range ( & exp, delta, HRTIMER_MODE_ABS) )
2384 break ;
2385 }
2386 }
2387 EXPORT_SYMBOL ( usleep_range) ;
2172 int __sched schedule_hrtimeout_range ( ktime_t * expires, u64 delta, const enum hrtimer_mode mode)
2174 {
2175 return schedule_hrtimeout_range_clock ( expires, delta, mode, CLOCK_MONOTONIC) ;
2177 }
2178 EXPORT_SYMBOL_GPL ( schedule_hrtimeout_range) ;
2275 int __sched
2276 schedule_hrtimeout_range_clock ( ktime_t * expires, u64 delta,
2277 const enum hrtimer_mode mode, clockid_t clock_id)
2278 {
2279 struct hrtimer_sleeper t;
2280
2281
2285 if ( expires && * expires == 0 ) {
2286 __set_current_state ( TASK_RUNNING) ;
2287 return 0 ;
2288 }
2289
2290
2293 if ( ! expires) {
2294 schedule ( ) ;
2295 return - EINTR;
2296 }
2302 if ( rt_task ( current) )
2303 delta = 0 ;
2304
2305 hrtimer_init_sleeper_on_stack ( & t, clock_id, mode) ;
2306 hrtimer_set_expires_range_ns ( & t. timer, * expires, delta) ;
2307 hrtimer_sleeper_start_expires ( & t, mode) ;
2308
2309 if ( likely ( t. task) )
2310 schedule ( ) ;
2311
2312 hrtimer_cancel ( & t. timer) ;
2313 destroy_hrtimer_on_stack ( & t. timer) ;
2314
2315 __set_current_state ( TASK_RUNNING) ;
2316
2317 return ! t. task ? 0 : - EINTR;
2318 }
2319 EXPORT_SYMBOL_GPL ( schedule_hrtimeout_range_clock) ;
hrtimer定时器分析
1 、定义struct hrtimer_sleeper t;
135 struct hrtimer_sleeper {
136 struct hrtimer timer;
137 struct task_struct * task;
138 } ;
38 enum hrtimer_mode {
39 HRTIMER_MODE_ABS = 0x00 ,
40 HRTIMER_MODE_REL = 0x01 ,
41 HRTIMER_MODE_PINNED = 0x02 ,
42 HRTIMER_MODE_SOFT = 0x04 ,
43 HRTIMER_MODE_HARD = 0x08 ,
2 、hrtimer_init_sleeper_on_stack ( & t, clock_id, mode) ;
443 void hrtimer_init_sleeper_on_stack ( struct hrtimer_sleeper * sl,
444 clockid_t clock_id, enum hrtimer_mode mode)
445 {
446 debug_object_init_on_stack ( & sl-> timer, & hrtimer_debug_descr) ;
447 __hrtimer_init_sleeper ( sl, clock_id, mode) ;
448 }
449 EXPORT_SYMBOL_GPL ( hrtimer_init_sleeper_on_stack) ;
1799 static void __hrtimer_init_sleeper ( struct hrtimer_sleeper * sl,
1800 clockid_t clock_id, enum hrtimer_mode mode)
1801 {
1821 if ( IS_ENABLED ( CONFIG_PREEMPT_RT) ) {
1822 if ( task_is_realtime ( current) && ! ( mode & HRTIMER_MODE_SOFT) )
1823 mode |= HRTIMER_MODE_HARD;
1824 }
1825
1826 __hrtimer_init ( & sl-> timer, clock_id, mode) ;
1827 sl-> timer. function = hrtimer_wakeup;
1828 sl-> task = current;
1829 }
1376 static void __hrtimer_init ( struct hrtimer * timer, clockid_t clock_id,
1377 enum hrtimer_mode mode)
1378 {
1379 bool softtimer = ! ! ( mode & HRTIMER_MODE_SOFT) ;
1380 struct hrtimer_cpu_base * cpu_base;
1381 int base;
1389 if ( IS_ENABLED ( CONFIG_PREEMPT_RT) && ! ( mode & HRTIMER_MODE_HARD) )
1390 softtimer = true;
1391
1392 memset ( timer, 0 , sizeof ( struct hrtimer ) ) ;
1393
1394 cpu_base = raw_cpu_ptr ( & hrtimer_bases) ;
1395
1401 if ( clock_id == CLOCK_REALTIME && mode & HRTIMER_MODE_REL)
1402 clock_id = CLOCK_MONOTONIC;
1403
1404 base = softtimer ? HRTIMER_MAX_CLOCK_BASES / 2 : 0 ;
1405 base += hrtimer_clockid_to_base ( clock_id) ;
1406 timer-> is_soft = softtimer;
1407 timer-> is_hard = ! softtimer;
1408 timer-> base = & cpu_base-> clock_base[ base] ;
1409 timerqueue_init ( & timer-> node) ;
1410 }
3 、hrtimer_set_expires_range_ns ( & t. timer, * expires, delta) ;
251 static inline void hrtimer_set_expires_range_ns ( struct hrtimer * timer, ktime_t time, u64 delta)
252 {
253 timer-> _softexpires = time;
254 timer-> node. expires = ktime_add_safe ( time, ns_to_ktime ( delta) ) ;
255 }
4 、hrtimer_sleeper_start_expires ( & t, mode) ;
1782 void hrtimer_sleeper_start_expires ( struct hrtimer_sleeper * sl,
1783 enum hrtimer_mode mode)
1784 {
1792 if ( IS_ENABLED ( CONFIG_PREEMPT_RT) && sl-> timer. is_hard)
1793 mode |= HRTIMER_MODE_HARD;
1794
1795 hrtimer_start_expires ( & sl-> timer, mode) ;
1796 }
1797 EXPORT_SYMBOL_GPL ( hrtimer_sleeper_start_expires) ;
426 static inline void hrtimer_start_expires ( struct hrtimer * timer,
427 enum hrtimer_mode mode)
428 {
429 u64 delta;
430 ktime_t soft, hard;
431 soft = hrtimer_get_softexpires ( timer) ;
432 hard = hrtimer_get_expires ( timer) ;
433 delta = ktime_to_ns ( ktime_sub ( hard, soft) ) ;
434 hrtimer_start_range_ns ( timer, soft, delta, mode) ;
435 }