From 3eaac95c0f86248b41bbfbe38f42c17f1047649b Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Wed, 24 May 2017 09:57:49 +0100 Subject: [PATCH] poll sketch --- README.md | 6 ++++ kernel_module/debugfs.c | 2 +- kernel_module/fops.c | 4 ++- kernel_module/poll.c | 75 +++++++++++++++++++++++++++++++++++++++ kernel_module/test/poll.c | 37 +++++++++++++++++++ rootfs_overlay/poll.sh | 3 ++ run | 2 +- 7 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 kernel_module/poll.c create mode 100644 kernel_module/test/poll.c create mode 100755 rootfs_overlay/poll.sh diff --git a/README.md b/README.md index 8117dcb..9954eff 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,11 @@ Each module comes from a C file under `kernel_module/`. For module usage see: head kernel_module/*.c +Good bets inside guest are: + + /modulename.sh + /modulename.out + After the first build, you can also run just: ./runqemu @@ -221,6 +226,7 @@ ARM TODOs: 1. [debugfs](kernel_module/debugfs.c) 1. [panic](kernel_module/panic.c) 1. [fops](kernel_module/fops.c) + 1. [poll](poll.c) 1. Asynchronous 1. [workqueue](kernel_module/workqueue.c) 1. [sleep](kernel_module/sleep.c) diff --git a/kernel_module/debugfs.c b/kernel_module/debugfs.c index f983156..43fe9a1 100644 --- a/kernel_module/debugfs.c +++ b/kernel_module/debugfs.c @@ -14,7 +14,7 @@ Requires `CONFIG_DEBUG_FS=y`. MODULE_LICENSE("GPL"); -static struct dentry *dir = 0; +static struct dentry *dir; static u32 value = 42; int init_module(void) diff --git a/kernel_module/fops.c b/kernel_module/fops.c index 996964f..539f43c 100644 --- a/kernel_module/fops.c +++ b/kernel_module/fops.c @@ -5,6 +5,8 @@ Usage: /fops.sh +The buffer can be written and read from. If data overflows, data is thrown away. + No, there ain't no official docs: http://stackoverflow.com/questions/15213932/what-are-the-struct-file-operations-arguments @@ -25,7 +27,7 @@ Here we use debugfs. MODULE_LICENSE("GPL"); -static struct dentry *dir = 0; +static struct dentry *dir; static char data[] = {'a', 'b', 'c', 'd'}; diff --git a/kernel_module/poll.c b/kernel_module/poll.c new file mode 100644 index 0000000..181c64b --- /dev/null +++ b/kernel_module/poll.c @@ -0,0 +1,75 @@ +/* +Basic poll file_operation example. + +Waits for a second, give jiffies to user, wait for a second... + +usleep_range +*/ + +#include /* copy_from_user, copy_to_user */ +#include +#include /* usleep_range */ +#include /* EFAULT */ +#include +#include +#include /* min */ +#include +#include +#include +#include /* printk */ + +MODULE_LICENSE("GPL"); + +static struct dentry *dir; +static struct task_struct *kthread; +static wait_queue_head_t waitqueue; + +static ssize_t read(struct file *file, char __user *buf, size_t len, loff_t *off) +{ + ssize_t ret; + char s[1024]; + + ret = snprintf(s, sizeof(s), "%llu", (unsigned long long)jiffies); + if (copy_to_user(buf, s, ret)) { + ret = -EFAULT; + } + return ret; +} + +unsigned int poll(struct file *filp, struct poll_table_struct *wait) +{ + /*TODO*/ + /*wait_event_interruptible(waitqueue, (dev->rp != dev->wp));*/ + pr_info("poll_wait before\n"); + poll_wait(filp, &waitqueue, wait); + pr_info("poll_wait after\n"); + return POLLIN; +} + +static int kthread_func(void *data) +{ + while (!kthread_should_stop()) { + usleep_range(1000000, 1000001); + wake_up_interruptible(&waitqueue); + } + return 0; +} + +static const struct file_operations fops = { + .read = read, + .poll = poll +}; + +int init_module(void) +{ + dir = debugfs_create_dir("kernel_module_cheat_poll", 0); + debugfs_create_file("f", 0666, dir, NULL, &fops); + init_waitqueue_head(&waitqueue); + kthread = kthread_create(kthread_func, NULL, "mykthread"); + return 0; +} + +void cleanup_module(void) +{ + debugfs_remove_recursive(dir); +} diff --git a/kernel_module/test/poll.c b/kernel_module/test/poll.c new file mode 100644 index 0000000..66f4589 --- /dev/null +++ b/kernel_module/test/poll.c @@ -0,0 +1,37 @@ +#define _XOPEN_SOURCE 700 +#include /* creat, O_CREAT */ +#include /* poll */ +#include /* printf, puts, snprintf */ +#include /* EXIT_FAILURE, EXIT_SUCCESS */ +#include /* read */ + +int main(int argc, char **argv) { + char buf[1024]; + int fd, n; + short revents; + struct pollfd pfd; + + fd = open(argv[1], O_RDONLY | O_NONBLOCK); + pfd.fd = fd; + pfd.events = POLLIN; + while (1) { + puts("loop"); + poll(&pfd, 1, -1); + revents = pfd.revents; + if (revents & POLLIN) { + n = read(pfd.fd, buf, sizeof(buf)); + printf("POLLIN n=%d buf=%.*s\n", n, n, buf); + } + if (revents & POLLHUP) { + printf("POLLHUP\n"); + close(pfd.fd); + break; + } + if (revents & POLLNVAL) { + printf("POLLNVAL\n"); + } + if (revents & POLLERR) { + printf("POLLERR\n"); + } + } +} diff --git a/rootfs_overlay/poll.sh b/rootfs_overlay/poll.sh new file mode 100755 index 0000000..a48283b --- /dev/null +++ b/rootfs_overlay/poll.sh @@ -0,0 +1,3 @@ +#!/bin/sh +insmod /poll.ko +/poll.out /sys/kernel/debug/kernel_module_cheat_poll/f diff --git a/run b/run index 1c19438..d477d4a 100755 --- a/run +++ b/run @@ -2,7 +2,7 @@ set -e cd buildroot arch='x86_64' -while getopts a: OPT; do +while getopts a: OPT > /dev/null 2>&1; do case "$OPT" in a) arch=$OPTARG