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 }