治肾虚不含糖,专注内核性能优化二十年。 https://github.com/KnightKu
分类: LINUX
2013-05-15 10:10:18
原文地址:linux2.6.32.2仿造proc文件系统dmsg 作者:angrad
linux2.6.32.2在proc文件系统下创建proc节点的函数是
proc_create("mybuf", S_IRUSR, NULL, &proc_mybuf_operations);
对应的移除函数是
remove_proc_entry("mybuf", NULL);
与创建的/proc/mybuf操作相关的函数是proc_mybuf_operations,这个跟字符设备操作函数一样.
因为我们要创建自定义myprintk打印信息的存储点/proc/mybuf,只需要设置读函数
.read = mybuf_read。
要模拟dmsg的实现,需要定义一个环形缓冲区。当缓冲区满了,旧的消息总会被新的消息代替。
为了每次cat /proc/mybuf时都能读到存入的打印信息,必须保存一个指向数据头的标记,
这个标记就是new_r_idx,分析循环缓冲区
{
Point1.当循环缓冲区满时,改变new_r_idx的指针
Point2.当循环缓冲区不满时,用r_idx作为读指针
Point3.r_idx的初值应该每次都从new_r_idx取
Point4.因为移动的是r_idx,所以判断是否读完循环缓冲区,应该用r_idx和w_idx比较
}
myprintk其实是效仿sprintf,将输入的数据先放入tmp_buf,再按循环缓冲区的规则存入cycle_buf,
用户cat /proc/mybuf时,就会调用mybuf_read读循环缓冲区cycle_buf. 其中如果没有数据就会休眠,
直到有其它程序调用myprintk写入数据,并唤醒队列。
需注意,自己写的myprintk函数要在其它驱动程序调用,必须在本驱动中
EXPORT_SYMBOL(myprintk);
而在调用驱动程序中
extern int myprintk;
完整驱动程序如下:
#include
#include
#include
#include
#include
#include
#include
#define LEN 1024
static char tmp_buf[LEN ];
static char cycle_buf[LEN];
static int w_idx;
static int r_idx;
static int new_r_idx;
static DECLARE_WAIT_QUEUE_HEAD(mylog_wait);
static int is_cyclebuf_empty(void)
{
return r_idx == w_idx;
}
static int cycle_buf_len(void)
{
return ((w_idx+LEN)-r_idx) % LEN;
}
static int is_finish_read()
{
return r_idx == w_idx; //Point4
}
static int is_cyclebuf_full(void)
{
return ((w_idx+1) % LEN) == new_r_idx; // Point1
}
static char cyclebuf_getchr(void)
{
char c = cycle_buf[r_idx]; //Point2
r_idx = (r_idx+1) % LEN;
return c;
}
static void cyclebuf_putchr(char c)
{
if (is_cyclebuf_full()) {
new_r_idx = (new_r_idx+1) % LEN;
}
cycle_buf[w_idx] = c;
w_idx = (w_idx+1) % LEN;
wake_up_interruptible(&mylog_wait);
}
ssize_t mybuf_read (struct file *filp, char __user *buf, size_t size, loff_t *offset)
{
int i = 0, error;
size = min(cycle_buf_len(), size);
r_idx = new_r_idx; //Point3
if ((filp->f_flags & O_NONBLOCK) && is_cyclebuf_empty())
return -EAGAIN;
error = wait_event_interruptible(mylog_wait,!is_cyclebuf_empty());
while (!error &&!is_finish_read()&& i < size) {
error = __put_user(cyclebuf_getchr(),buf);
buf++;
i++;
}
if (!error)
error = i;
return error;
}
static const struct file_operations proc_mybuf_operations = {
.read = mybuf_read,
};
int myprintk(const char *fmt, ...)
{
va_list args;
int i, j;
va_start(args, fmt);
i=vsnprintf(tmp_buf, INT_MAX, fmt, args);
va_end(args);
for(j=0; j
cyclebuf_putchr(tmp_buf[j]);
}
return i;
}
static int myprintk_init(void)
{
proc_create("mybuf", S_IRUSR, NULL, &proc_mybuf_operations);
return 0;
}
static void myprintk_exit(void)
{
remove_proc_entry("mybuf", NULL);
return ;
}
module_init(myprintk_init);
module_exit(myprintk_exit);
EXPORT_SYMBOL(myprintk);
MODULE_LICENSE("GPL");
测试程序:
first_drv.c,简单的字符驱动程序,包括一个open函数,里面定义一个静态int cnt,用于计数.
testapp.c,应用程序调用simple_drv里面的open函数,每次运行./testapp都会让静态cnt加1,再cat /proc/mybuf就可以看到实验现象。
2012-05-14 02:20 发表于百度空间,今搬至CU。