本篇内容介绍了“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 proc_dir_entry *entry; //这里创建了一个proc入口kmsg entry = create_proc_entry("kmsg", S_IRUSR, &proc_root); if (entry) 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); 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 int is_mylog_empty_for_read(void) { return (mylog_r_tmp == mylog_w); } static void mylog_putc(char c) { if(is_mylog_full()) { mylog_r= (mylog_r + 1) % MYLOG_BUF_LEN; if((mylog_r_tmp + 1)% MYLOG_BUF_LEN == mylog_r) mylog_r_tmp= mylog_r; } mylog_buf[mylog_w]= c; mylog_w= (mylog_w + 1) % MYLOG_BUF_LEN; wake_up_interruptible(&mymsg_waitq); } 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; } 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; if ((file->f_flags & O_NONBLOCK) && is_mylog_empty()) return -EAGAIN; error= wait_event_interruptible(mymsg_waitq, !is_mylog_empty_for_read()); 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); *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, .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_class= class_create(THIS_MODULE, "firstdrv"); firstdrv_class_dev= class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); gpfcon= (volatile unsigned long *)ioremap(0x56000050, 16); gpfdat= gpfcon + 1; return 0; } static void first_drv_exit(void) { unregister_chrdev(major,"first_drv"); // 卸载 class_device_unregister(firstdrv_class_dev); class_destroy(firstdrv_class); iounmap(gpfcon); } module_init(first_drv_init); module_exit(first_drv_exit); MODULE_LICENSE("GPL");
6、在tty中测试效果
# insmod my_msg.ko # insmod first_drv.ko # cat /proc/mymsg mymsg_open mylog_r_tmp=0 first_drv_init
“Linux的proc怎么使用”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!