diff --git a/kernel_module/poll.c b/kernel_module/poll.c index f7957cb..9cca31d 100644 --- a/kernel_module/poll.c +++ b/kernel_module/poll.c @@ -1,9 +1,7 @@ /* -TODO now yet waiting for anything! + /poll.sh -Basic poll file_operation example. - -Waits for a second, give jiffies to user, wait for a second... +Outcome: user echoes jiffies every second. */ #include /* copy_from_user, copy_to_user */ @@ -21,37 +19,46 @@ Waits for a second, give jiffies to user, wait for a second... MODULE_LICENSE("GPL"); +static char readbuf[1024]; +static size_t readbuflen; 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) +static ssize_t read(struct file *filp, 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)) { + 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. + +This gets called again every time an event happens in the wait queue. +*/ 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; + if (readbuflen) + return POLLIN; + else + 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); - wake_up_interruptible(&waitqueue); + wake_up(&waitqueue); } return 0; } @@ -64,14 +71,16 @@ static const struct file_operations fops = { static int myinit(void) { dir = debugfs_create_dir("lkmc_poll", 0); - debugfs_create_file("f", 0666, dir, NULL, &fops); + debugfs_create_file("f", 0666, dir, 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_recursive(dir); } diff --git a/kernel_module/test/poll.c b/kernel_module/test/poll.c index 66f4589..bc1a5d3 100644 --- a/kernel_module/test/poll.c +++ b/kernel_module/test/poll.c @@ -6,32 +6,29 @@ #include /* read */ int main(int argc, char **argv) { - char buf[1024]; - int fd, n; + char buf[1024], path[1024]; + int fd, i, n; short revents; struct pollfd pfd; 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("loop"); - poll(&pfd, 1, -1); + i = poll(&pfd, 1, -1); + if (i == -1) { + perror("poll"); + exit(EXIT_FAILURE); + } 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/kernel_module/wait_queue.c b/kernel_module/wait_queue.c index b9130ce..e927456 100644 --- a/kernel_module/wait_queue.c +++ b/kernel_module/wait_queue.c @@ -1,7 +1,7 @@ /* "wait_event" works a bit like: - if (!cond) + while (!cond) sleep_until_event Outcome: diff --git a/rungdb b/rungdb index 7017253..88dbd6e 100755 --- a/rungdb +++ b/rungdb @@ -22,7 +22,7 @@ else fi gdb="$(pwd)/buildroot/output/host/usr/bin/${arch}-linux-gdb" -cd buildroot/output/build/linux-*.*.*/ +cd buildroot/output/build/linux-?.*.*/ if $kgdb; then cmd="$gdb \ -q \