Skip to content

Instantly share code, notes, and snippets.

@mts0629
Created September 29, 2019 10:05
Show Gist options
  • Save mts0629/8344af19e09ae003b779006769c65502 to your computer and use it in GitHub Desktop.
Save mts0629/8344af19e09ae003b779006769c65502 to your computer and use it in GitHub Desktop.
example of kernel module: one-shot timer
// ****************************************
// timer_kern_module.c
// based on: https://windhole.booth.pm/items/1169009
// ****************************************
#include <linux/module.h>
#include <linux/debugfs.h>
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("John Doe");
MODULE_DESCRIPTION("A simple example of interval timer");
static struct dentry *topdir;
static struct dentry *testfile;
// buffer for reading/writing data on kernel space
static char testbuf[128];
// one-shot timer
struct timer_list mytimer;
static DEFINE_MUTEX(mytimer_mutex);
// timeout[ms]
static unsigned long mytimer_timeout_msecs = 1000 * 1000;
// display message on timeout
static void mytimer_fn(struct timer_list *timer)
{
printk(KERN_ALERT "%lu secs passed.\n", mytimer_timeout_msecs / 1000);
}
// show remaining time
static ssize_t mytimer_remain_msecs_read(struct file *f, char __user *buf, size_t len, loff_t *ppos)
{
unsigned long diff_msecs, now = jiffies;
mutex_lock(&mytimer_mutex);
if (time_after(mytimer.expires, now)) {
diff_msecs = (mytimer.expires - now) * 1000 / HZ;
} else {
diff_msecs = 0;
}
mutex_unlock(&mytimer_mutex);
snprintf(testbuf, sizeof(testbuf), "%lu\n", diff_msecs);
return simple_read_from_buffer(buf, len, ppos, testbuf, strlen(testbuf));
}
// change timeout[ms]
static ssize_t mytimer_remain_msecs_write(struct file *f, const char __user *buf, size_t len, loff_t *ppos)
{
ssize_t ret;
mutex_lock(&mytimer_mutex);
ret = simple_write_to_buffer(testbuf, sizeof(testbuf), ppos, buf, len);
if (ret < 0) {
mutex_unlock(&mytimer_mutex);
return ret;
}
sscanf(testbuf, "%20lu", &mytimer_timeout_msecs);
mod_timer(&mytimer, jiffies + mytimer_timeout_msecs * HZ / 1000);
mutex_unlock(&mytimer_mutex);
return ret;
}
// debugfs interfaces
// read remaining time: $ sudo cat /sys/kernel/debug/mytimer/remain_msecs
// change timeout: $ sudo echo [timeout] > /sys/kernel/debug/mytimer/remain_msecs
static struct file_operations test_fops = {
.owner = THIS_MODULE,
.read = mytimer_remain_msecs_read,
.write = mytimer_remain_msecs_write,
};
static int mymodule_init(void)
{
timer_setup(&mytimer, mytimer_fn, 0);
mytimer.expires = jiffies + mytimer_timeout_msecs * HZ / 1000;
add_timer(&mytimer);
topdir = debugfs_create_dir("mytimer", NULL);
if (!topdir) {
return -ENOMEM;
}
testfile = debugfs_create_file("remain_msecs", 0660, topdir, NULL, &test_fops);
if (!testfile) {
return -ENOMEM;
}
return 0;
}
static void mymodule_exit(void)
{
debugfs_remove_recursive(topdir);
del_timer(&mytimer);
}
module_init(mymodule_init);
module_exit(mymodule_exit);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment