本文共 3070 字,大约阅读时间需要 10 分钟。
上一节的程序很振奋人心,我们自己实现了一个myprintk打印函数。但是这个函数存在一个致命的缺陷,那就是只能使用一次cat /proc/mymsg命令来读取mylog_buf的值。这是因为读到最后会出现:mylog_r == mylog_w,表示缓冲区为空,下一次就不能在读到数据了。在本节里面我们就着手来解决这个问题,我们要实现的就是每次使用 cat /proc/mymsg 时,都会从头打印。那么我们就需要将入口做一个拷贝,一个保存起来,一个进行变换。这样的话,当下一次读的时候,我们可以将保存的入口重新做个拷贝,然后让拷贝进行变化。具体程序如下:
#include <linux/module.h> #include <linux/kernel.h> #include <asm/arch/regs-gpio.h> #include <asm/hardware.h> #include <linux/proc_fs.h> #define MYLOG_BUF_LEN 1024 struct proc_dir_entry *myentry; static char mylog_buf[MYLOG_BUF_LEN]; static char tmp_buf[MYLOG_BUF_LEN]; static int mylog_r_for_read = 0;//这个用来拷贝mylog_r ,它将改变,但是mylog_r 不变 static DECLARE_WAIT_QUEUE_HEAD(mymsg_waitq); static int is_mylog_empty(void) return (mylog_r == mylog_w); static int is_mylog_empty_for_read(void) return (mylog_r_for_read == mylog_w); static int is_mylog_full(void) return ((mylog_w + 1)% MYLOG_BUF_LEN == mylog_r); static void mylog_putc(char c) mylog_r = (mylog_r + 1) % MYLOG_BUF_LEN; /*加上下面三行的原因是:如果读的时候,也一直在调用printk写的话, *当写的速度比较快的时候,可能会导致mylog_w超过mylog_r_for_read, *这时就需要更新mylog_r_for_read,使mylog_r_for_read 指向新的入口 *当mylog_w超过入口mylog_r时,mylog_r会一直跟着更新的! if ((mylog_r_for_read + 1) % MYLOG_BUF_LEN == mylog_r) mylog_r_for_read = mylog_r; mylog_w = (mylog_w + 1) % MYLOG_BUF_LEN; wake_up_interruptible(&mymsg_waitq); static int mylog_getc_for_read (char *p) if ( is_mylog_empty_for_read ()) *p = mylog_buf[ mylog_r_for_read ]; mylog_r_for_read = ( mylog_r_for_read + 1) % MYLOG_BUF_LEN; int myprintk(const char *fmt, ...) i = vsnprintf(tmp_buf, INT_MAX, fmt, args); static ssize_t mymsg_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)
if ((file->f_flags & O_NONBLOCK) && is_mylog_empty_for_read()) error = wait_event_interruptible(mymsg_waitq, !is_mylog_empty_for_read()); while (!error && ( mylog_getc_for_read (&c)) && i < count) { error = __put_user(c, buf); static int mymsg_open(struct inode *inode, struct file *file) mylog_r_for_read = mylog_r; const struct file_operations proc_mymsg_operations = { static int mymsg_init(void) myentry = create_proc_entry("mymsg", S_IRUSR, &proc_root); myentry->proc_fops = &proc_mymsg_operations; static void mymsg_exit(void) remove_proc_entry("mymsg", &proc_root); 总结,关于这个函数,当我们在用户空间,使用命令:cat /proc/mymsg时,首先会调用open函数,在open函数里面会将入口做一个拷贝,然后拿出一份来作为变化量,另外一个作为入口不改变。这样,每次cat /proc/mymsg时,都会从入口处开始打印! 转载地址:http://jpbql.baihongyu.com/