- How to Setup a Periodic Timer Callback in a Linux Kernel Module
- How to setup a periodic timer callback in a Linux kernel module
- How to add a periodic timer callback in a linux kernel module
- Calling mod_timer from inside timer callback function
- kernel module to collect data from UART with periodic kernel timer (jiffies or hrtimer)
- How to use timers in Linux kernel device drivers?
- 3 Answers 3
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/
#include
#include
#include
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
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:
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)
How to use timers in Linux kernel device drivers?
I want to implement a counter in Linux device drivers which increments after every fixed interval of time. I want to do this with the help of timers. A sample code snippet would be very useful.
How often do you want to increment this? Why you even need this? (there are some counters here already, e.g. jiffles )
@Pat The OP is asking how to create a timer in kernel space. While setitimer sets a timer in user space.
3 Answers 3
There is a small example of how to use Linux kernel timers (included it here for convenience, comments are from myself, removed printk messages)
#include #include #include MODULE_LICENSE("GPL"); static struct timer_list my_timer; void my_timer_callback( unsigned long data ) < /* do your timer stuff here */ >int init_module(void) < /* setup your timer to call my_timer_callback */ setup_timer(&my_timer, my_timer_callback, 0); /* setup timer interval to 200 msecs */ mod_timer(&my_timer, jiffies + msecs_to_jiffies(200)); return 0; >void cleanup_module(void) < /* remove kernel timer when unloading module */ del_timer(&my_timer); return; >
My «edit queue is full», so I can’t post this fixed link to the IBM blog post: developer.ibm.com/tutorials/l-timers-list
Around Linux kernel 4.15 release, void setup_timer(timer, function, data); became obsolete with an intent to remove it completely.
Instead, now we have to use
void timer_setup( struct timer_list *timer, void (*callback)(struct timer_list *), unsigned int flags );
This can be found in linux/timer.h file.
Here’s a full example of module_with_timer.c
#include #include #include #include MODULE_LICENSE("GPL"); static struct timer_list my_timer; void my_timer_callback(struct timer_list *timer) < printk(KERN_ALERT "This line is printed after 5 seconds.\n"); >static int init_module_with_timer(void) < printk(KERN_ALERT "Initializing a module with timer.\n"); /* Setup the timer for initial use. Look in linux/timer.h for this function */ timer_setup(&my_timer, my_timer_callback, 0); mod_timer(&my_timer, jiffies + msecs_to_jiffies(5000)); return 0; >static void exit_module_with_timer(void) < printk(KERN_ALERT "Goodbye, cruel world!\n"); del_timer(&my_timer); >module_init(init_module_with_timer); module_exit(exit_module_with_timer);
obj-m = module_with_timer.o # Get the current kernel version number KVERSION = $(shell uname -r) all: make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules clean: make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean
Note: In real life programming, it is better to check the version of the kernel we are compiling for and then use an then appropriately start the timer.