千家信息网

Linux的proc怎么使用

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,本篇内容介绍了"Linux的proc怎么使用"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1、简介在
千家信息网最后更新 2026年11月01日Linux的proc怎么使用

本篇内容介绍了"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) /*构造一个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  #include #include #include #include #include #include #include #include #include #include  #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  #include #include #include #include #include #include #include #include #include  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_class= class_create(THIS_MODULE, "firstdrv");      firstdrv_class_dev= class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/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怎么使用"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

队列 数据 环形 空间 内核 程序 位置 数组 结构 循环 输出 字符 文件 时候 休眠 元素 内容 单位 实际 很快 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 中关村互联网科技集团 新华互联网科技学校 疫情对互联网科技公司影响 互联网为科技 互联网金融公司科技 互联网科技英文 齐家互联网科技 奇酷互联网络科技公司 互联网和高科技公司 中国科技互联网公司收入 互联网系的金融科技公司 互联网科技项目计划书材料类 全球顶尖互联网科技公司 宜昌元轩互联网科技有限公司 广州市恰铎互联网科技有限公司 开一家科技互联网公司需要多少钱 工业互联网等科技实现智能化赋能 九思连强互联网电子科技有限公司 西安有哪些互联网高科技企业 六子台科技互联网展会 手冲咖啡和咖啡机区别 上海互联网科技有限公司 北京互联网科技公司 互联网 视角下的科技创新 创业天下互联网科技有限公司 互联网系的金融科技公司 开一家科技互联网公司需要多少钱 互联网公司黑科技创始人 银行科技岗属于互联网吗 北京天晋互联网科技有限公司
0