As I know, to inform the user space from kernel space, one way is to using poll. That means kernel driver should provide poll method first. Below code is found from internet, and it really works!
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Fortune Cookie Kernel Module");
MODULE_AUTHOR("M. Tim Jones");
#define MAX_COOKIE_LENGTH PAGE_SIZE
static struct proc_dir_entry *proc_entry;
static char *cookie_buf; // Space for fortune strings
static int write_index; // Index to write next fortune
static int read_index; // Index to read next fortune
ssize_t fortune_write( struct file *filp, const char __user *buff,
unsigned long len, void *data )
// Refer to: ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
{
int space_available = (MAX_COOKIE_LENGTH-write_index);
if (len > space_available) {
printk(KERN_INFO "fortune: cookie buffer is full!\n");
return -ENOSPC;
}
if (copy_from_user( &cookie_buf[write_index], buff, len )) {
return -EFAULT;
}
write_index += len;
cookie_buf[write_index-1] = 0;
return len;
}
ssize_t fortune_read(struct file *file, char *buf, size_t count, loff_t *f_pos){
// Refer to: ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
int len;
//there's no fortune or a fortune has already been read
//the *f_pos > 0 hack is needed because `cat /proc/fortune` would otherwise
//display every thing in the cookie_buf
if(write_index == 0 || *f_pos > 0){
return 0;
}
// cicle through fortunes
if(read_index >= write_index){
read_index = 0;
}
len = sprintf(buf, "%s\n", &cookie_buf[read_index]);
read_index += len;
*f_pos += len;
return len;
}
static const struct file_operations proc_test_fops = {
.owner = THIS_MODULE,
// .open = led_proc_open,
.read = fortune_read,
// .llseek = seq_lseek,
// .release = single_release,
.write = fortune_write,
// unsigned int (*poll) (struct file *, struct poll_table_struct *);
// int (*fasync) (int, struct file *, int);
};
int __init init_fortune_module( void )
{
int ret = 0;
cookie_buf = (char *)vmalloc( MAX_COOKIE_LENGTH );
if (!cookie_buf) {
ret = -ENOMEM;
} else {
memset( cookie_buf, 0, MAX_COOKIE_LENGTH );
// proc_entry = create_proc_entry( "fortune", 0644, NULL );
proc_entry = proc_create( "fortune", 0644, NULL, &proc_test_fops );
if (proc_entry == NULL) {
ret = -ENOMEM;
vfree(cookie_buf);
printk(KERN_INFO "fortune: Couldn't create proc entry\n");
} else {
write_index = 0;
read_index = 0;
printk(KERN_INFO "fortune: Module loaded.\n");
}
}
return ret;
}
void __exit exit_fortune_module( void )
{
// remove_proc_entry("fortune", &proc_entry);
proc_remove(proc_entry);
vfree(cookie_buf);
printk(KERN_INFO "fortune: Module unloaded.\n");
}
module_init( init_fortune_module );
module_exit( exit_fortune_module );
I can do like this to make it work:
echo "hello" > /proc/fortune
And then
cat /proc/fortune
to see the result.
But how to add poll method to it? I tried some times, but still failed.
Polling the device usually means reading its status register every so often until the device's status changes to indicate that it has completed the request.
When poll() is called for some file descriptor, the corresponding device poll_xyx() method registered with file operation structure is invoked in kernel space. This method then checks if the data is readily available, if this condition is true then the event mask is set and the poll returns to user space.
The poll_table structure, the second argument to the poll method, is used within the kernel to implement the poll and select calls; it is declared in <linux/poll. h> , which must be included by the driver source.
The select() call has you create three bitmasks to mark which sockets and file descriptors you want to watch for reading, writing, and errors, and then the operating system marks which ones in fact have had some kind of activity; poll() has you create a list of descriptor IDs, and the operating system marks each of ...
Minimal runnable example
GitHub upstream with QEMU + Buildroot boilerplate:
In this simplified example, we generate poll events from a separate thread. In real life, poll events will likely be triggered by interrupts, when the hardware has finished some job, and new data became available for userland to read.
The main point to remember is that if poll
returns zero, the kernel calls it again: Why do we need to call poll_wait in poll?
poll.ko
#include <linux/debugfs.h>
#include <linux/delay.h> /* usleep_range */
#include <linux/errno.h> /* EFAULT */
#include <linux/fs.h>
#include <linux/jiffies.h>
#include <linux/kernel.h> /* min */
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/printk.h> /* printk */
#include <linux/uaccess.h> /* copy_from_user, copy_to_user */
#include <linux/wait.h> /* wait_queue_head_t, wait_event_interruptible, wake_up_interruptible */
#include <uapi/linux/stat.h> /* S_IRUSR */
static int ret0 = 0;
module_param(ret0, int, S_IRUSR | S_IWUSR);
MODULE_PARM_DESC(i, "if 1, always return 0 from poll");
static char readbuf[1024];
static size_t readbuflen;
static struct dentry *debugfs_file;
static struct task_struct *kthread;
static wait_queue_head_t waitqueue;
static ssize_t read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
ssize_t ret;
if (copy_to_user(buf, readbuf, readbuflen)) {
ret = -EFAULT;
} else {
ret = readbuflen;
}
/* This is normal pipe behaviour: data gets drained once a reader reads from it. */
/* https://stackoverflow.com/questions/1634580/named-pipes-fifos-on-unix-with-multiple-readers */
readbuflen = 0;
return ret;
}
/* If you return 0 here, then the kernel will sleep until an event
* happens in the queue. and then call this again, because of the call to poll_wait. */
unsigned int poll(struct file *filp, struct poll_table_struct *wait)
{
pr_info("poll\n");
/* This doesn't sleep. It just makes the kernel call poll again if we return 0. */
poll_wait(filp, &waitqueue, wait);
if (readbuflen && !ret0) {
pr_info("return POLLIN\n");
return POLLIN;
} else {
pr_info("return 0\n");
return 0;
}
}
static int kthread_func(void *data)
{
while (!kthread_should_stop()) {
readbuflen = snprintf(
readbuf,
sizeof(readbuf),
"%llu",
(unsigned long long)jiffies
);
usleep_range(1000000, 1000001);
pr_info("wake_up\n");
wake_up(&waitqueue);
}
return 0;
}
static const struct file_operations fops = {
.owner = THIS_MODULE,
.read = read,
.poll = poll
};
static int myinit(void)
{
debugfs_file = debugfs_create_file(
"lkmc_poll", S_IRUSR | S_IWUSR, NULL, NULL, &fops);
init_waitqueue_head(&waitqueue);
kthread = kthread_create(kthread_func, NULL, "mykthread");
wake_up_process(kthread);
return 0;
}
static void myexit(void)
{
kthread_stop(kthread);
debugfs_remove(debugfs_file);
}
module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");
poll.out userland:
#define _XOPEN_SOURCE 700
#include <assert.h>
#include <fcntl.h> /* creat, O_CREAT */
#include <poll.h> /* poll */
#include <stdio.h> /* printf, puts, snprintf */
#include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS */
#include <unistd.h> /* read */
int main(int argc, char **argv) {
char buf[1024];
int fd, i, n;
short revents;
struct pollfd pfd;
if (argc < 2) {
fprintf(stderr, "usage: %s <poll-device>\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY | O_NONBLOCK);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
pfd.fd = fd;
pfd.events = POLLIN;
while (1) {
puts("poll");
i = poll(&pfd, 1, -1);
if (i == -1) {
perror("poll");
assert(0);
}
revents = pfd.revents;
printf("revents = %d\n", revents);
if (revents & POLLIN) {
n = read(pfd.fd, buf, sizeof(buf));
printf("POLLIN n=%d buf=%.*s\n", n, n, buf);
}
}
}
Usage:
insmod poll.ko
mount -t debugfs none /sys/kernel/debug
./kernel_modules/poll.out /sys/kernel/debug/lkmc_poll
Outcome: jiffies
gets printed to stdout every second from userland, e.g.:
poll
<6>[ 4.275305] poll
<6>[ 4.275580] return POLLIN
revents = 1
POLLIN n=10 buf=4294893337
poll
<6>[ 4.276627] poll
<6>[ 4.276911] return 0
<6>[ 5.271193] wake_up
<6>[ 5.272326] poll
<6>[ 5.273207] return POLLIN
revents = 1
POLLIN n=10 buf=4294893588
poll
<6>[ 5.276367] poll
<6>[ 5.276618] return 0
<6>[ 6.275178] wake_up
<6>[ 6.276370] poll
<6>[ 6.277269] return POLLIN
revents = 1
POLLIN n=10 buf=4294893839
Force the poll file_operation
to return 0 to see what happens more clearly:
insmod poll.ko ret0=1
Sample output:
poll
<6>[ 85.674801] poll
<6>[ 85.675788] return 0
<6>[ 86.675182] wake_up
<6>[ 86.676431] poll
<6>[ 86.677373] return 0
<6>[ 87.679198] wake_up
<6>[ 87.680515] poll
<6>[ 87.681564] return 0
<6>[ 88.683198] wake_up
From this we see that control is not returned to userland: the kernel just keeps calling the poll file_operation
again and again.
Tested on Linux 5.4.3.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With