How to Setup a Periodic Timer Callback in a Linux Kernel Module

How to setup a periodic timer callback in a Linux kernel module

Linux kernel high-resolution timer hrtimer is an option.
http://lwn.net/Articles/167897/

Here what I do:

#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <linux/sched.h>

static struct hrtimer htimer;
static ktime_t kt_periode;

static void timer_init(void)
{
kt_periode = ktime_set(0, 104167); //seconds,nanoseconds
hrtimer_init (& htimer, CLOCK_REALTIME, HRTIMER_MODE_REL);
htimer.function = timer_function;
hrtimer_start(& htimer, kt_periode, HRTIMER_MODE_REL);
}

static void timer_cleanup(void)
{
hrtimer_cancel(& htimer);
}

static enum hrtimer_restart timer_function(struct hrtimer * timer)
{
// @Do your work here.

hrtimer_forward_now(timer, kt_periode);

return HRTIMER_RESTART;
}

How to add a periodic timer callback in a linux kernel module


maybe there is a standard kernel API for that

Of course there is. Needing a timer in a kernel module is probably not unusual.

I don't know much about the API, but I do know it exists. If you are going to write a kernel module properly, you should get a book or something; there are several.1 Anyway, one traditional method would be:

#include <linux/timer.h>

schedule_timeout(jiffies);

That's a passive sleep. Jiffies are a unit based on a 250 HZ tick within the processor, although this may be configurable. That header has various other functions, here's a brief discussion involving the 2.6 kernel, but I would assume 3.x must still be compatible with this, since a lot of the source, including drivers, is older than that. There's an easy way to find out of course.

Jiffies is probably fine if you want a delay of a second. Granularity for passive sleeps on the millisecond level is a problem with a regular kernel because of scheduler latency, but there is a nanosecond granularity API too in ktime.h (that link is from a 2.6 kernel again, but the file is still dated 2005 in the 3.11 source, so has not changed). Keep in mind that linux also has userspace timers with nanosecond granularity, but this does not mean they will actually work for timing things on that level because of scheduler latency (and presumably this is also true for passive timers in kernel space).

You can access the RTC instead of using processor/kernel ticks, but there are some disadvantages:

  • Not all systems actually have one.
  • Implies busy looping.

And no real advantages. AFAIK the RTC is not considered more accurate than processor ticks.

1 Another resource you would be wise to make use of is the Linux Kernel Mailing List (LKML), which is where the devs are, and they do answer questions. Be warned the list has a volume into the hundreds of messages per day.

Calling mod_timer from inside timer callback function

Your function timer_start() will have to call add_timer() after it sets up the function and the expiration time. Once the timer function triggers, your timer is no longer active, so all you have to do is reset the .expires field to your new value and call add_timer() again. Be sure you provide a clean way to stop rescheduling the timer, for example on module unload.

send_now();
if(!terminate_timer) {
test_timer.expires = jiffies + HZ*get_interval();
add_timer(&test_timer);
}

kernel module to collect data from UART with periodic kernel timer (jiffies or hrtimer)

With the standard driver for rs232, there's no delay from the time you issue the write(2) system call to the time the kernel drivers begin outputting bytes to the serial line (remember the driver is running in kernel mode already). Writing a driver or kernel module for this will be error prone, will have to be maintained by you, and you'll need to be clever at kernel programming to do it well and not crash in the way (you 'll have to cope with the standard driver trying to get use of the port, as it is automatically done by the driver and your driver has to reserve the port for own use, to not interfere with it). Only in case you fill completely the buffer, your process will have to wait for the buffer to get empty, but by definition, this is not going to happen, as you cannot compensate (you are filling the output line quicker than the chars go out, and this will make your process to block once the buffer is full) for that and be real timer altogether, in that case. On input, you have a similar process. You'll have an input character that triggers some interrupt to take it from the device to the buffer, and this normally (if you configure VMIN to 1 on termio) means your process will be awaken immediately, on each character read (as soon as each character comes in) I recommend you to use VMIN set to 1 and VTIME set to 0 (read the standard termios(3) manual page for a full explanation of the serial driver) to awaken your process as soon as each character is received. Your process will be awaken and scheduled, depending on system load and cpu speed, but normally this means usecs in time for a normal up to date cpu. You can timestamp the reading as soon as you come from the read(2) call or try to get a read timestamp from the kernel in a separate ioctl(2) call to check when in time was the character received (I know this is possible in linux, at least for sockets, without needing to program a module for that) (but not when it was transmitted from the remote end, think on this) but I think to get msec timing, it's enough to do everything in user mode and not complicate things going into kernel mode. RS232 lines were no designed for realtime, so what you are trying can be ok with millisec resolution without going to program in kernel side.

In addition, doing all in user mode allows your program to move from system to system without having to do complex installations of kernel modules before trying your software, and even more.... knowing how to use the tty driver allow you to run your code in non-linux systems (like BSD, Solaris or MAC, for example)



Related Topics



Leave a reply



Submit