LDD3 chapter6 sleepy模块在源代码的 misc-modules文件夹中。是一个简单的休眠-唤醒的例子。
sleepy.c
/* * sleepy.c -- the writers awake the readers * * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet * Copyright (C) 2001 O'Reilly & Associates * * The source code in this file can be freely used, adapted, * and redistributed in source or binary form, so long as an * acknowledgment appears in derived source files. The citation * should list that the code comes from the book "Linux Device * Drivers" by Alessandro Rubini and Jonathan Corbet, published * by O'Reilly & Associates. No warranty is attached; * we cannot take responsibility for errors or fitness for use. * * $Id: sleepy.c,v 1.7 2004/09/26 07:02:43 gregkh Exp $ */ #include <linux/module.h> #include <linux/init.h> #include <linux/sched.h> /* current and everything */ #include <linux/kernel.h> /* printk() */ #include <linux/fs.h> /* everything... */ #include <linux/types.h> /* size_t */ #include <linux/wait.h> MODULE_LICENSE("Dual BSD/GPL"); static int sleepy_major = 0; static DECLARE_WAIT_QUEUE_HEAD(wq); static int flag = 0; ssize_t sleepy_read (struct file *filp, char __user *buf, size_t count, loff_t *pos) { printk(KERN_DEBUG "process %i (%s) going to sleep\n", current->pid, current->comm); wait_event_interruptible(wq, flag != 0); flag = 0; printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm); return 0; /* EOF */ } ssize_t sleepy_write (struct file *filp, const char __user *buf, size_t count, loff_t *pos) { printk(KERN_DEBUG "process %i (%s) awakening the readers...\n", current->pid, current->comm); flag = 1; wake_up_interruptible(&wq); return count; /* succeed, to avoid retrial */ } struct file_operations sleepy_fops = { .owner = THIS_MODULE, .read = sleepy_read, .write = sleepy_write, }; int sleepy_init(void) { int result; /* * Register your major, and accept a dynamic number */ result = register_chrdev(sleepy_major, "sleepy", &sleepy_fops); if (result < 0) return result; if (sleepy_major == 0) sleepy_major = result; /* dynamic */ return 0; } void sleepy_cleanup(void) { unregister_chrdev(sleepy_major, "sleepy"); } module_init(sleepy_init); module_exit(sleepy_cleanup);
KERN_DIR = /run/media/huntinux/F/huntinux_work/embeded_world/linux_kernel/mini2440-linux2.6.32.2 all: make -C $(KERN_DIR) M=`pwd` modules clean: make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.order install: cp *.ko /nfs/busybox/fs_mini2440 obj-m := sleepy.o
/nfs/busybox/fs_mini2440 是网络文件系统的根目录。
在pc机上
#make #make install
插入模块,并查询主设备号。(应为是动态分配,所以需要查询得到主设备号,然后使用该主设备号创建设备节点)
# insmod sleepy.ko
# cat /proc/devices | grep "sleepy" 253 sleepy
# mknod /dev/sleepy c 253 0
# cat /dev/sleepy &发现process ... going to sleep 没有打印出来。
原因很简单: 当前日志级别的数值 小于 KERN_DEBUG。数值越小优先级越高。见LDD chapter4 讲解printk的内容。
解决办法:修改当前日志级别为8即可:
# echo 8 >/proc/sys/kernel/printk # cat /dev/sleepy & process 680 (cat) going to sleep对/dev/sleepy读的设备会休眠。
# echo "data">/dev/sleepy process 657 (sh) awakening the readers... awoken 678 (cat)写/dev/sleepy 会唤醒休眠的进程。
此外,手动创建节点太麻烦,与书上前几章的方法一样,用脚本实现自动创建节点。
sleey_load.sh:
#!/bin/sh module="sleepy" device="sleepy" mode="664" /sbin/insmod ./$module.ko $* || exit 1 major=$(awk "\$2==\"$module\" {print \$1}" /proc/devices) rm -f /dev/${device} mknod /dev/${device} c $major 0