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

I am writing a kernel module in which I need to trigger a function on a periodic basis. The function will access a queue and process its elements. The number of elements in the queue is dynamic and so the processing time.

In the following code, I have added 1ms sleep to represent the processing time. I am getting this error : [116588.117966] BUG: scheduling while atomic: systemd-journal/408/0x00010000. If my understanding is correct, this happens since I try to sleep 1ms when the expiry time of the hr_timer is just 1us. I can increase this expiry time but the processing time of the queue can be sometimes more than seconds, sometimes in hours even. Please help me to achieve this.

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;
}

Upvotes: 1

Views: 3051

Answers (1)

Federico
Federico

Reputation: 3892

BUG: scheduling while atomic

This message means that while you are in an atomic context you tried to schedule some other task.

To make it easy (so, not perfect and orthodox explanation): if a function is running in an atomic context, this function cannot stop its execution and call the scheduler (a.k.a. sleeping).

When you call msleep(1) you are actually asking the kernel to schedule some other task because for 1 millisecond you do not have anything to do and you ask the kernel to use this time to do something useful. But this is not allowed in an atomic context. Functions running in an atomic context must finish their execution without any interruption.

Another example of function that will sleep and you may have the temptation to use is kmalloc. If you need it in an atomic context then use the GFP_ATOMIC flag in order to have an atomic allocation that does not sleep (schedule).

Another example of atomic context is the interrupt handler function.

Another problem that you may have with msleep(1) is that is not guaranteed that it will sleep 1 millisecond. It it too short to be guaranteed. Indeed, it is suggested to use a sleeping time greater or equal than 20 milliseconds. If you need a shorter sleeping time, then use delay functions.

Read The following links:

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

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

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

Upvotes: 4

Related Questions