Created
September 29, 2019 10:05
-
-
Save mts0629/8344af19e09ae003b779006769c65502 to your computer and use it in GitHub Desktop.
example of kernel module: one-shot timer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// **************************************** | |
// 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