Linux的proc怎么使用

71次阅读
没有评论

共计 5854 个字符,预计需要花费 15 分钟才能阅读完成。

本篇内容介绍了“Linux 的 proc 怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让丸趣 TV 小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

1、简介

在内核中使用 printk 可以讲调试信息保存在 log_buf 缓冲区中,可以使用命令 #cat /proc/kmsg   将缓冲区的数区的数数据打印出来, 自己写 kmsg 这个文件,我们取名叫做 mymsg。

2、查看内核中 /proc/kmsg 怎么写的!

在 Proc_misc.c (fs\proc) 文件中:

void __init proc_misc_init(void){ ......................... struct proc_dir_entry *entry; // 这里创建了一个 proc 入口 kmsg entry = create_proc_entry( kmsg , S_IRUSR,  proc_root); if (entry) /* 构造一个 proc_fops 结构 */ entry- proc_fops =  proc_kmsg_operations;......................... }

在 Kmsg.c (fs\proc) 文件中:

const struct file_operations proc_kmsg_operations = { .read = kmsg_read, .poll = kmsg_poll, .open = kmsg_open, .release = kmsg_release,};

在用户空间中使用 cat  /proc/kmsg 的时候,会调用 kmsg_open,在调用 kmsg_read 函数,读取 log_buf 中的数据,拷贝到用户空间显示。

3、在写之前,我们需要来学习一下循环队列

环形队列是在实际编程极为有用的数据结构,它有如下特点:

它是一个首尾相连的 FIFO 的数据结构,采用数组的线性空间,数据组织简单,能很快知道队列是否满为空。能以很快速度的来存取数据。

因为有简单高效的原因,甚至在硬件都实现了环形队列。

环形队列广泛用于网络数据收发,和不同程序间数据交换 (比如内核与应用程序大量交换数据,从硬件接收大量数据) 均使用了环形队列。

3.1. 环形队列实现原理

内存上没有环形的结构,因此环形队列实上是数组的线性空间来实现。那当数据到了尾部如何处理呢? 它将转回到 0 位置来处理。这个的转回是通过取模操作来执行的。

因此环列队列的是逻辑上将数组元素 q[0]与 q[MAXN-1]连接,形成一个存放队列的环形空间。

为了方便读写,还要用数组下标来指明队列的读写位置。head/tail. 其中 head 指向可以读的位置,tail 指向可以写的位置。

环形队列的关键是判断队列为空,还是为满。当 tail 追上 head 时,队列为满时,当 head 追上 tail 时,队列为空。但如何知道谁追上谁。还需要一些辅助的手段来判断.

如何判断环形队列为空,为满有两种判断方法。

(1)是附加一个标志位 tag

当 head 赶上 tail,队列空,则令 tag=0,

当 tail 赶上 head,队列满,则令 tag=1,

(2)限制 tail 赶上 head,即队尾结点与队首结点之间至少留有一个元素的空间。

队列空:head==tail

队列满:(tail+1)% MAXN ==head

4、程序编写

#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 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 int mylog_r_tmp = 0; /* 休眠队列初始化 */ static DECLARE_WAIT_QUEUE_HEAD(mymsg_waitq); /* * 判断环形队列是否为空  * 返回 0: 表示不空   返回 1: 表示空  */ static int is_mylog_empty(void) { return (mylog_r == mylog_w); } /* * 判断环形队列是否满  * 返回 0: 表示不满   返回 1: 表示满  */ static int is_mylog_full(void) { return((mylog_w + 1)% MYLOG_BUF_LEN == mylog_r); } /* * 在读取的时候,判断环形队列中数据是否为空  * 返回 0: 表示不空   返回 1: 表示空  */ static int is_mylog_empty_for_read(void) { return (mylog_r_tmp == mylog_w); } /* * 往循环队列中存字符  * 输入:c 字符   单位:1byte * 输出: 无  */ static void mylog_putc(char c) { if(is_mylog_full()) { /* 如果检测到队列已经满了,则丢弃该数据 */ mylog_r= (mylog_r + 1) % MYLOG_BUF_LEN; /*mylog_r_tmp 不能大于 mylog_r*/ if((mylog_r_tmp + 1)% MYLOG_BUF_LEN == mylog_r) mylog_r_tmp= mylog_r; } mylog_buf[mylog_w]= c; /* 当 mylog_w=1023 的时候  (mylog_w+1) % MYLOG_BUF_LEN =0, 回到队列头,实现循环 */ mylog_w= (mylog_w + 1) % MYLOG_BUF_LEN; /*  唤醒等待数据的进程 */ wake_up_interruptible(mymsg_waitq); } /* * 从循环队列中读字符  * 输入:*p  单位:1byte * 输出:1 表示成功  */ static int mylog_getc(char *p) { /* 判断数据是否为空 */ if (is_mylog_empty_for_read()) { return 0; } *p = mylog_buf[mylog_r_tmp ]; mylog_r_tmp = (mylog_r_tmp + 1) % MYLOG_BUF_LEN; return 1; } /* * 调用 myprintk,和 printf 用法相同  */ 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; size_t i=0; char c; /*  把 mylog_buf 的数据 copy_to_user, return*/ /* 非阻塞   和   缓冲区为空的时候返回 */ if ((file- f_flags   O_NONBLOCK)   is_mylog_empty()) return -EAGAIN; /* 休眠队列 wait_event_interruptible(xxx,0)-- 休眠 */ error= wait_event_interruptible(mymsg_waitq, !is_mylog_empty_for_read()); /* copy_to_user*/ while (!error   (mylog_getc( 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_tmp= mylog_r; return 0; } const struct file_operations proc_mymsg_operations = { .read= mymsg_read, .open= mymsg_open, }; static int mymsg_init(void) { struct proc_dir_entry *myentry; kmsg 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

5、测试程序

注意: 在上面程序中 使用了 EXPORT_SYMBOL(myprintk); 意思是把 myprintk 可以在整个内核空间使用。

使用方法:

①extern int myprintk(const char *fmt, …); 声明

② myprintk(first_drv_open : %d\n , ++cnt); 使用

#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  static struct class *firstdrv_class; static struct class_device *firstdrv_class_dev; volatile unsigned long *gpfcon = NULL; volatile unsigned long *gpfdat = NULL; extern int myprintk(const char *fmt, ...); static int first_drv_open(struct inode *inode, struct file *file) { static int cnt = 0; myprintk( first_drv_open : %d\n , ++cnt); /*  配置 GPF4,5,6 为输出 */ *gpfcon  = ~((0x3 (4*2)) | (0x3 (5*2)) | (0x3 (6*2))); *gpfcon |= ((0x1 (4*2)) | (0x1 (5*2)) | (0x1 (6*2))); return 0; } static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) { int val; static int cnt = 0; myprintk( first_drv_write : %d\n , ++cnt); copy_from_user(val, buf, count); // copy_to_user(); if (val == 1) { //  点灯  *gpfdat  = ~((1 4) | (1 5) | (1 6)); } else { //  灭灯  *gpfdat |= (1 4) | (1 5) | (1 6); } return 0; } static struct file_operations first_drv_fops = { .owner = THIS_MODULE, /*  这是一个宏,推向编译模块时自动创建的__this_module 变量 */ .open = first_drv_open, .write = first_drv_write, }; int major; static int first_drv_init(void) { myprintk( first_drv_init\n  major= register_chrdev(0,  first_drv ,  first_drv_fops); //  注册,  告诉内核  firstdrv_ >

6、在 tty 中测试效果

# insmod my_msg.ko # insmod first_drv.ko # cat /proc/mymsg mymsg_open mylog_r_tmp=0 first_drv_init

“Linux 的 proc 怎么使用”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注丸趣 TV 网站,丸趣 TV 小编将为大家输出更多高质量的实用文章!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-16发表,共计5854字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)