所以我们接下来要做的就是来完成这个读函数,而这这个读函数里面我们要做的就是将mylog_buf中的中的数据拷贝到用户空间。有一个很关键的地方就是,我们的
mylog_buf 应该是一个环形队列,关于环形队列的概念我们先来说一下:
#include
#include
#include
#include
#include
#include
#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 = 0; //用来标识读
static int mylog_w = 0; //用来标识写
static
DECLARE_WAIT_QUEUE_HEAD(mymsg_waitq);
//判断环形缓冲区是否为空
static int is_mylog_empty(void)
{
return (mylog_r
== mylog_w);
}
//判断环形缓冲区是否已满
static int is_mylog_full(void)
{
return ((mylog_w
+ 1)% MYLOG_BUF_LEN == mylog_r);
}
/*写缓冲区:如果缓冲区已满的话,就让覆盖掉下一个要读的数据
*否则就直接写入
此外在写缓冲区函数里面还需要做的一件事情就是唤醒等待队列,
这是因为当缓冲区为空的时候,如果调用读函数的话,就会使进程
进入等待队列,理当在写入数据的时候唤醒进程
*/
static void mylog_putc(char c)
{
if
(is_mylog_full())
{
/* 丢弃一个数据 */
mylog_r =
(mylog_r + 1) % MYLOG_BUF_LEN;
}
mylog_buf[mylog_w] =
c;
mylog_w =
(mylog_w + 1) % MYLOG_BUF_LEN;
/* 唤醒等待数据的进程
*/
wake_up_interruptible(&mymsg_waitq);
/* 唤醒休眠的进程 */
}
/*读缓冲区:如果缓冲区为空的话,就返回0
否则从首部读出一个数据,返回1
*/
static int mylog_getc(char *p)
{
if
(is_mylog_empty())
{
return
0;
}
*p =
mylog_buf[mylog_r];
mylog_r =
(mylog_r + 1) % MYLOG_BUF_LEN;
return
1;
}
/*打印函数:这个函数是参考sprintf函数得编写的
*它将传递进来的参数转换为固定的格式之后,放入到一个临时缓冲区里面
*然后将环形缓冲区的值写入到mylog_buf缓冲区里面,详见注释2
*/
int myprintk(const char *fmt, ...)
{
va_list
args;
int
i;
int
j;
va_start(args,
fmt);
i =
vsnprintf(tmp_buf, INT_MAX, fmt, args);//将传进来的参数转换后放入tmp_buf
va_end(args);
for (j = 0; j
< i; j++)
mylog_putc(tmp_buf[j]);//将tmp_buf里面的东东放入mylog_buf缓冲区里面
return
i;
}
/*读函数:当在应用空间调用命令:cat
/proc/mymsg的时候,会调用这个函数
*
*/
static ssize_t mymsg_read(struct file *file, char
__user *buf,
size_t count,
loff_t *ppos)
{
int error =
0;
int i =
0;
char
c;
/* 把mylog_buf的数据copy_to_user, return */
//如果为非阻塞且mylog_buf为空,那么就出错返回
if
((file->f_flags & O_NONBLOCK) && is_mylog_empty())
return
-EAGAIN;
//如果mylog_buf为空的话进程进入等待队列,还记得我们在写缓冲区
//函数里面会唤醒进程这件事情吧!
error =
wait_event_interruptible(mymsg_waitq, !is_mylog_empty());
/* copy_to_user */
//首先从缓冲区里面获得一个字符,然后拷贝到用户空间
//如果缓冲区还有信息的话,就再次获得字符,拷贝到用户
//空间,直到缓冲区为空
while (!error
&& (mylog_getc(&c)) && i < count) {
error =
__put_user(c, buf);//将c的内容拷贝到用户空间
buf++;
i++;
}
if
(!error)
error =
i;
return
error;
}
const struct file_operations proc_mymsg_operations =
{
.read =
mymsg_read,
};
static int mymsg_init(void)
{
myentry =
create_proc_entry("mymsg", S_IRUSR, &proc_root);
if
(myentry)
myentry->proc_fops =
&proc_mymsg_operations;
return
0;
}
static void mymsg_exit(void)
{
remove_proc_entry("mymsg",
&proc_root);
}
module_init(mymsg_init);
module_exit(mymsg_exit);
/*因为myprintk是我们自己写的打印语句
*所以需要导出才能被使用,使用的时候还需要声明一下:
extern int
myprintk(const char *fmt,...);
*/
EXPORT_SYMBOL(myprintk);
MODULE_LICENSE("GPL");