驱动程序调试方法之printk——自制proc文件(二)

上一节的程序很振奋人心,我们自己实现了一个myprintk打印函数。但是这个函数存在一个致命的缺陷,那就是只能使用一次cat /proc/mymsg命令来读取mylog_buf的值。这是因为读到最后会出现:mylog_r == mylog_w,表示缓冲区为空,下一次就不能在读到数据了。在本节里面我们就着手来解决这个问题,我们要实现的就是每次使用 cat /proc/mymsg 时,都会从头打印。那么我们就需要将入口做一个拷贝,一个保存起来,一个进行变换。这样的话,当下一次读的时候,我们可以将保存的入口重新做个拷贝,然后让拷贝进行变化。具体程序如下:

 

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <linux/init.h>

#include <linux/delay.h>

#include <asm/uaccess.h>

#include <asm/irq.h>

#include <asm/io.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 = 0;

static int mylog_r_for_read = 0;//这个用来拷贝mylog_r ,它将改变,但是mylog_r 不变

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_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);

}

 

//这个函数是被myprintk函数调用的

static void mylog_putc(char c)

{

if (is_mylog_full())

{

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_buf[mylog_w] = c;

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())

{

return 0;

}

*p = mylog_buf[mylog_r_for_read];

mylog_r_for_read = (mylog_r_for_read + 1) % MYLOG_BUF_LEN;

return 1;

}

 

 

int myprintk(const char *fmt, ...)

{

va_list args;

int i;

int j;

 

va_start(args, fmt);

i = vsnprintf(tmp_buf, INT_MAX, fmt, args);

va_end(args);

 

for (j = 0; j < i; j++)

mylog_putc(tmp_buf[j]);

 

return i;

}

 

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;

 

if ((file->f_flags & O_NONBLOCK) && is_mylog_empty_for_read())

return -EAGAIN;

 

error = wait_event_interruptible(mymsg_waitq, !is_mylog_empty_for_read());

 

/* copy_to_user */

while (!error && (mylog_getc_for_read(&c)) && i < count) {

error = __put_user(c, buf);

buf++;

i++;

}

 

if (!error)

error = i;

 

return error;

}

 

static int mymsg_open(struct inode *inode, struct file *file)

{

mylog_r_for_read = mylog_r;

return 0;

}

 

const struct file_operations proc_mymsg_operations = {

.open = mymsg_open,

.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);

 

EXPORT_SYMBOL(myprintk);

 

MODULE_LICENSE("GPL");

 

总结,关于这个函数,当我们在用户空间,使用命令:cat /proc/mymsg时,首先会调用open函数,在open函数里面会将入口做一个拷贝,然后拿出一份来作为变化量,另外一个作为入口不改变。这样,每次cat /proc/mymsg时,都会从入口处开始打印!

时间: 2024-10-01 23:58:53

驱动程序调试方法之printk——自制proc文件(二)的相关文章

驱动程序调试方法之printk——自制proc文件(一)

首先我们需要弄清楚proc机制,来看看fs/proc/proc_misc.c这个文件,从入口函数开始看: proc_misc_init(void)         #ifdef CONFIG_PRINTK { struct proc_dir_entry *entry; entry = create_proc_entry("kmsg", S_IRUSR, &proc_root);//这里创建了一个proc入口kmsg if (entry) entry->proc_fops

Linux下core文件调试方法

在程序不寻常退出时,内核会在当前工作目录下生成一个core文件(是一个内存映像,同时加上调试信息).使用gdb来查看core文件,可以指示出导致程序出错的代码所在文件和行数. 1.core文件的生成开关和大小限制  1)使用ulimit -c命令可查看core文件的生成开关.若结果为0,则表示关闭了此功能,不会生成core文件.  2)使用ulimit -c filesize命令,可以限制core文件的大小(filesize的单位为kbyte).若ulimit -c unlimited,则表示c

Linux内核调试技术之自构proc

1.简介 在内核中使用printk可以讲调试信息保存在log_buf缓冲区中,可以使用命令 #cat /proc/kmsg 将缓冲区的数区的数数据打印出来,今天我们就来研究一下,自己写kmsg这个文件,我们取名叫做 mymsg. 2.查看内核中 /proc/kmsg怎么写的! 在Proc_misc.c (fs\proc) 文件中: void __init proc_misc_init(void){      .........................          struct pr

Ubuntu中为Android系统上编写Linux内核驱动程序实现方法_Android

        在智能手机时代,每个品牌的手机都有自己的个性特点.正是依靠这种与众不同的个性来吸引用户,营造品牌凝聚力和用户忠城度,典型的代表非iphone莫属了.据统计,截止2011年5月,AppStore的应用软件数量达381062个,位居第一,而Android Market的应用软件数量达294738,紧随AppStore后面,并有望在8月份越过AppStore.随着Android系统逐步扩大市场占有率,终端设备的多样性亟需更多的移动开发人员的参与.据业内统计,Android研发人才缺口至

Ubuntu中为Android系统上编写Linux内核驱动程序实现方法

在智能手机时代,每个品牌的手机都有自己的个性特点.正是依靠这种与众不同的个性来吸引用户,营造品牌凝聚力和用户忠城度,典型的代表非iphone莫属了.据统计,截止2011年5月,AppStore的应用软件数量达381062个,位居第一,而Android Market的应用软件数量达294738,紧随AppStore后面,并有望在8月份越过AppStore.随着Android系统逐步扩大市场占有率,终端设备的多样性亟需更多的移动开发人员的参与.据业内统计,Android研发人才缺口至少30万.目前,

VxWorks操作系统shell命令与调试方法总结

VxWorks下的调试手段 主要介绍在Tornado集成开发环境下的调试方法和利用支撑定位问题的步骤.思路. 1         Tornado的调试工具 嵌入式实时操作系统VxWorks和集成开发环境Tornado的组成结构如下图1.分为主机和目标机系统. 图1 集成开发环境结构图 在Tornado下调试相关操作在Debug菜单下包括 图2 Debug菜单 简单解释各菜单项的功能 1.1        WindShell 1.1.1         简介 Vxworks的Shell分为两种ho

Linux下的段错误产生的原因及调试方法

Linux下的段错误产生的原因及调试方法     简而言之,产生段错误就是访问了错误的内存段,一般是你没有权限,或者根本就不存在对应的物理内存,尤其常见的是访问0地址. 一般来说,段错误就是指访问的内存超出了系统所给这个程序的内存空间,通常这个值是由gdtr来保存的,他是一个48位的寄存器,其中的32位是保存由它指向的gdt表,后13位保存相应于gdt的下标,最后3位包括了程序是否在内存中以及程序的在cpu中的运行级别,指向的gdt是由以64位为一个单位的表,在这张表中就保存着程序运行的代码段以

php程序调试方法总结

  相信很多朋友们都有调试程序的经历,然而很多时候调试程序是痛苦而又漫长的过程;它不仅需要细心,更需要耐心,切忌心浮气躁.但是当找出问题并顺利解决它时,又会给人无比激动的喜悦.这里总结一下笔者在程序调试中的使用的原则,工具,以及方法.这里需要说明的是,某些原则性的东西,各种语言都是差不多的,而涉及到具体的工具和某些具体的调试方法,这里只涉及web开发方面的内容. 总体原则: 1.找出问题原因: 程序需要调试,是因为程序有问题.而调试的第一目标是找到原因.常见调试方法, 排除法: 当我们面对整个复

visual studio-关于Visual Studio2015调试无法查找或打开PDF文件的问题

问题描述 关于Visual Studio2015调试无法查找或打开PDF文件的问题 如图,已连接源服务器也没有用,求教如何调好 解决方案 不是pdf文件,是pdb文件.这个是调试符号.没有调试符号不影响你调试的. 解决方案二: Visual Studio ""无法查找或打开PDB文件""解决方法Visual Studio调试之符号文件Visual Studio调试之符号文件