如果回调函数的处理时间是动态的,如何使用hrtimer?

How to use hrtimer if the processing time of the callback function is dynamic?

我正在编写一个内核模块,我需要在其中定期触发一个函数。该函数将访问队列并处理其元素。队列中的元素数量是动态的,处理时间也是如此。

在下面的代码中,我添加了 1ms sleep 来表示处理时间。我收到此错误:[116588.117966] BUG: scheduling while atomic: systemd-journal/408/0x00010000。如果我的理解是正确的,那么发生这种情况是因为当 hr_timer 的到期时间仅为 1us 时我尝试休眠 1ms。我可以增加这个到期时间,但队列的处理时间有时可能超过几秒,有时甚至几小时。请帮我实现这个目标。

unsigned long timer_interval_ns = 1e3;
static struct hrtimer hr_timer;

enum hrtimer_restart timer_callback( struct hrtimer *timer_for_restart )
{
    uint64_t rawtime;
    struct timespec curtime;
    ktime_t currtime , interval;

    / * My Operations would take ~ 1ms, so adding 1ms for simplicity* /
    msleep(1);

    currtime = ktime_get();
    interval = ktime_set(0,timer_interval_ns);

    hrtimer_forward(timer_for_restart, currtime, interval);

    return HRTIMER_RESTART;
}

static int __init timer_init(void) {
    ktime_t ktime = ktime_set( 0, timer_interval_ns );
    hrtimer_init( &hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
    hr_timer.function = &timer_callback;
    hrtimer_start( &hr_timer, ktime, HRTIMER_MODE_REL );
    return 0;
}

BUG: scheduling while atomic

此消息意味着当您处于 原子上下文 中时,您试图安排其他任务。

为了简单起见(所以,不是完美和正统的解释):如果一个函数在原子上下文中是运行,这个函数不能停止它的执行和调用调度程序 (a.k.a.sleeping).

当您调用 msleep(1) 时,您实际上是在要求内核安排其他任务,因为在 1 毫秒内您无事可做,您要求内核利用这段时间做一些有用的事情。但这在 原子上下文 中是不允许的。原子上下文 中的函数 运行 必须 不间断地完成它们的执行。

另一个会休眠且您可能会想使用的函数示例是 kmalloc。如果您在原子上下文中需要它,请使用 GFP_ATOMIC 标志以获得不休眠(计划)的原子分配。

原子上下文的另一个例子是中断处理函数。

您可能遇到的另一个问题 msleep(1) 是不能保证它会休眠 1 毫秒。它太短了,无法保证。实际上,建议使用大于或等于 20 毫秒的休眠时间。如果您需要更短的睡眠时间,请使用延迟功能。

阅读以下链接:

https://en.wikipedia.org/wiki/Linearizability

https://lwn.net/Articles/274695/

https://www.kernel.org/doc/Documentation/timers/timers-howto.txt