Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1253060
  • 博文数量: 185
  • 博客积分: 495
  • 博客等级: 下士
  • 技术积分: 1418
  • 用 户 组: 普通用户
  • 注册时间: 2012-09-02 15:12
个人简介

治肾虚不含糖,专注内核性能优化二十年。 https://github.com/KnightKu

文章分类

全部博文(185)

文章存档

2019年(1)

2018年(12)

2017年(5)

2016年(23)

2015年(1)

2014年(22)

2013年(82)

2012年(39)

分类: LINUX

2013-05-15 10:10:18


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。



阅读(1245) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~