linux seq_file 文件编程步骤

在上面我们介绍了使用 seq_file 需要实现的一些函数和相关结构体,现在我们把它们组合起来,介绍以下
通过 proc 来使用 seq_file 的一般步骤,而 seq_file 在其他方面的应用方法也是一样的。
(1) 实现 seq_operations ,也就是前面我们介绍的 seq_file 的底层数据操作函数集,示例如下:
static struct seq_operations proc_seq_ops = {
.start = proc_seq_start,
.next = proc_seq_next,
.stop = proc_seq_stop,
.show = proc_seq_show
};
这些回调函数都是需要根据你所要获取的序列数据结构来实现的。
(2) 实现 struct file_operations 中的 open 函数,这个 open 函数的实现也是非常简单固定格式,无私有数据
情况实例如下:
static int proc_seq_open(struct inode *inode, struct file *file)
{
return seq_open(file, &proc_seq_ops);
};
seq_open 的实现如下,此函数实现在 seq_file.c 中。
int seq_open(struct file *file, const struct seq_operations *op)

struct seq_file *p;
WARN_ON(file->private_data);
p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
file->private_data = p;
mutex_init(&p->lock);
p->op = op;
// No refcounting: the lifetime of 'p' is constrained
// to the lifetime of the file.
p->file = file;
/*
* Wrappers around seq_open(e.g. swaps_open) need to be
* aware of this. If they set f_version themselves, they
* should call seq_open first and then set f_version.
*/
file->f_version = 0;
/*
* seq_files support lseek() and pread(). They do not implement
* write() at all, but we clear FMODE_PWRITE here for historical
* reasons.
*
* If a client of seq_files a) implements file.write() and b) wishes to
* support pwrite() then that client will need to implement its own
* file.open() which calls seq_open() and then sets FMODE_PWRITE.
*/
file->f_mode &= ~FMODE_PWRITE;
return 0;
}
seq_file 结构会在 seq_open 中申请,并附在 file 的私有数据成员 private_data 中。可以看到,一般就是使用
seq_file 中的一个 API:seq_open,目的是向 seq_file 结构体中注册一个 struct seq_operations 。
另外还有 int seq_open_private(struct file *filp, const struct seq_operations *ops,int psize)函数,此函数会为
seq_file 的私有数据申请空间。
若需要私有数据可使用 seq_open_private 接口。
(3) 实现 struct file_operations proc_ops,示例如下:
static struct file_operations proc_ops = {
.owner = THIS_MODULE,
.open = proc_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
大家可以看到,以上的 read、llseek、release 都是有 seq_file 提供的接口函数,直接注册即可,唯有 open 是
需要自己实现的。

在 seq 中是没有实现 write 操作的,因此,如果根据需要添加 write 操作,需要再 file_ops 中单独添加。
(4)注册 proc 文件,注册包含 seq_file 操作函数的 file_operations 结构体到 proc_fops。我的测试程序中的实
例代码如下:
……
proc_test_entry = create_proc_entry("proc_seq", 0644, NULL);
if (proc_test_entry == NULL) {
ret = -ENOMEM;
cleanup_test_data();
pr_err("proc_test: Couldn't create proc entry\n");
} else {
proc_test_entry->proc_fops = &proc_ops;
pr_info("proc_test: Module loaded.\n");
}

示例

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/kernel_stat.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#define MAX_CPU_NUM 32
#define RPT_LINE_MAXLEN 1024
unsigned int last_user[MAX_CPU_NUM];
unsigned int last_system[MAX_CPU_NUM];
unsigned int last_nice[MAX_CPU_NUM];
unsigned int last_idle[MAX_CPU_NUM];
unsigned int last_si[MAX_CPU_NUM];
unsigned int last_hi[MAX_CPU_NUM];
static struct proc_dir_entry *monitor_root_dir;
static struct proc_dir_entry *proc_tos;
#define LEFT(x) (((unsigned)x) / 10)
#define RIGHT(x) (((unsigned)x) % 10)
#define SEQ_START_TOKEN ((void *)1)
static void *tos_get_cpuinfo_start(struct seq_file *f, loff_t *pos)
{
void *v = NULL;
v = *pos ? pos : SEQ_START_TOKEN;
return v;
}
static int tos_get_cpuinfo_show(struct seq_file *f, void *v)
{
unsigned int user=0, system=0, nice=0, idle=0, si = 0, hi = 0;

unsigned int sum;
int cpu_num = num_possible_cpus();
int i;
if (v == SEQ_START_TOKEN){
for(i=0;i<cpu_num;i++){
user = kcpustat_cpu(i).cpustat[CPUTIME_USER]-last_user[i];
nice = kcpustat_cpu(i).cpustat[CPUTIME_NICE]-last_nice[i];
system = kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM]-last_system[i];
idle = kcpustat_cpu(i).cpustat[CPUTIME_IDLE]-last_idle[i];
si = kcpustat_cpu(i).cpustat[CPUTIME_SOFTIRQ]-last_si[i];
hi = kcpustat_cpu(i).cpustat[CPUTIME_IRQ]-last_hi[i];
sum = user+nice+system+idle + si + hi;
if(sum==0){
user=1;
nice = 0;
system =89;
idle = 10;
si = 0;
hi = 0;
sum = user+nice+system+idle + si + hi;
}
seq_printf(f, "CPU Load
Information:(%d %s)\n",cpu_num,cpu_num>1?"cpus":"cpu");
seq_printf(f," cpu%d:\n",i);
seq_printf(f, "%-18s%u.%u%%\n", " User",
LEFT(user*1000/sum),
RIGHT(user*1000/sum));
seq_printf(f, "%-18s%u.%u%%\n", " System",
LEFT(system*1000/sum),
RIGHT(system*1000/sum));
seq_printf(f, "%-18s%u.%u%%\n"," Nice",
LEFT(nice*1000/sum),
RIGHT(nice*1000/sum));
seq_printf(f, "%-18s%u.%u%%\n"," Si",
LEFT(si*1000/sum),
RIGHT(si*1000/sum));
seq_printf(f, "%-18s%u.%u%%\n"," Hi",
LEFT(hi*1000/sum),
RIGHT(hi*1000/sum));
seq_printf(f, "%-18s%u.%u%%\n"," Idle",
LEFT(idle*1000/sum),
RIGHT(idle*1000/sum));
}
seq_printf(f, "\n");

}
return 0;
}
static void *tos_get_cpuinfo_next(struct seq_file *f, void *v, loff_t *pos)
{
(*pos)++;
return v == SEQ_START_TOKEN ? NULL : NULL;//只获取一次
}
static void tos_get_cpuinfo_stop(struct seq_file *f, void *v)
{
/* Nothing to do */
}
static const struct seq_operations tos_get_cpuinfo_sops = {
.start = tos_get_cpuinfo_start,
.next = tos_get_cpuinfo_next,
.stop = tos_get_cpuinfo_stop,
.show = tos_get_cpuinfo_show
};
static int tos_get_cpuinfo_open(struct inode *inode, struct file *filp)
{
return seq_open(filp, &tos_get_cpuinfo_sops);
}
static const struct file_operations tos_get_cpuinfo_fopes = {
.open = tos_get_cpuinfo_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int __init tos_get_cpuinfo_init(void)
{
static struct proc_dir_entry *entry;
proc_tos = proc_mkdir("tos", 0);
if (!proc_tos) {
printk("tos proc mkdir tos failed!\n");
return -1;
}
monitor_root_dir = proc_mkdir("tos/monitor", NULL);
if(monitor_root_dir == NULL){
printk("tos/monitor proc mkdir tos failed!\n");
if(proc_tos)
remove_proc_entry("tos", NULL);
return -ENOMEM;
}
entry = proc_create("cpu", 0644, monitor_root_dir, &tos_get_cpuinfo_fopes);
if(!entry) {
printk("create_proc_entry error");

if(monitor_root_dir)
remove_proc_entry("tos/monitor", NULL);
if(proc_tos)
remove_proc_entry("tos", NULL);
return -1;
}
return 0;
}
static void __exit tos_get_cpuinfo_exit(void)
{
remove_proc_entry("cpu", monitor_root_dir);
if(monitor_root_dir)
remove_proc_entry("tos/monitor", NULL);
if(proc_tos)
remove_proc_entry("tos", NULL);
}
MODULE_LICENSE("GPL");
module_init(tos_get_cpuinfo_init);
module_exit(tos_get_cpuinfo_exit);
复杂的示例可阅读内核源码 fib_trie.c,查看路由的 proc 文件的实现,其中遍历路由树时使用的自己的迭代
器,迭代器在 seq->private 记录。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/604477.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springMvc向request作用域存储数据的4种方式

文章目录 目录1、springmvc使用ServletAPI向request作用域共享数据&#xff08;原生态&#xff09;2、springmvc使用ModelAndView向request作用域共享数据3、springmvc使用Model向request作用域共享数据4、springmvc使用map向request作用域共享数据5、springmvc使用ModelMap向r…

VMware Workstation——快照

目录 一、为什么要使用快照 二、拍摄快照 三、快照管理 1、克隆 2、转到 ​3、删除 一、为什么要使用快照 VMware虚拟机的快照是一个很重要的功能。 简单点说它相当于某个时刻虚拟的备份&#xff0c;并且可以快速还原至原来的状态。但是它和备份还是有区别的。 【快照…

Java集合框架深度解析:HashMap

Java中的HashMap是一种基于哈希表的实现&#xff0c;提供了快速的查找性能。在这篇深度解析中&#xff0c;我们将深入探讨HashMap**的实现原理、适用场景、潜在问题以及并发控制策略。 1. HashMap的实现原理 1.1 哈希表 HashMap内部基于哈希表实现&#xff0c;通过散列函数将…

基于移动群智感知的网络信号图谱构建系统

一&#xff0e;项目研究内容 本项目基于移动群智感知技术的群体感知特性&#xff0c;利用手机的GSM/3G/4G/5G/WiFi等通信模块可以采集不同位置的移动蜂窝网络基站等网络基础设施的信号覆盖数据&#xff0c;充分发动人民群众&#xff0c;携带安装有感知功能软件的智能手机在环境…

软件装一送三了!还附带弹窗资讯,你确定不试一下?

前言 前几天一个朋友向我吐槽&#xff0c;说电脑太卡了。自己好像都没安装什么软件&#xff0c;怎么就那么多弹窗广告。 我看了一下他的电脑&#xff0c;笑了一下说&#xff1a;你的电脑真好&#xff0c;都会只能给你推荐美女看&#xff0c;这资讯来之不易啊&#xff0c;好好享…

数据库开发与设计过程中的问题分析总结

数据库设计的过程是将数据库系统与现实世界密切地、有机地、协调一致地结合起来的过程。数据库的设计质量与设计者的知识、经验和水平密切相关。作为数据库应用系统的重要组成部分&#xff0c;数据库设计的成败往往直接关系到整个应用系统的成败。以数据库为基础的数据库应用系…

【JaveWeb教程】(8)Web前端基础:Vue组件库Element之Table表格组件和Pagination分页组件 详细示例介绍

目录 1 Table表格组件1.1 组件演示1.2 组件属性详解 2 Pagination分页2.1 组件演示2.2 组件属性详解2.3 组件事件详解 接下来我们来学习一下ElementUI的常用组件&#xff0c;对于组件的学习比较简单&#xff0c;我们只需要参考官方提供的代码&#xff0c;然后复制粘贴即可。本节…

WebStorm 创建一个Vue项目

一、下载并安装WebStorm 步骤一 步骤二 选择激活方式 激活码&#xff1a; I2A0QUY8VU-eyJsaWNlbnNlSWQiOiJJMkEwUVVZOFZVIiwibGljZW5zZWVOYW1lIjoiVU5JVkVSU0lEQURFIEVTVEFEVUFMIERFIENBTVBJTkFTIiwiYXNzaWduZWVOYW1lIjoiVGFvYmFv77yaSkVU5YWo5a625qG25rAIOa0uW3peS9nOWup…

docker安装 mysql

一、安装docker# windows 和 mac 版可以直接到官网下载 docker desktop linux 的安装方法可以参考 https://www.cnblogs.com/myzony/p/9071210.html 可以在shell中输入以下命令检查是否成功安装&#xff1a; sudo docker version 二、建立镜像# 拉取官方镜像&#xff08;我…

0.9uA 低功耗低压差稳压器

一、基本概述 FM6215 系列采用 CMOS 工艺制造的高精度、低功耗低压差稳压器。该系列具有极低的静态电流, 输出电压 3.3v的产品静态功耗仅为 0.9uA(TYP),最大输出电流可达到 300mA。 产品采用 SOT23-5 封装&#xff0c;因此&#xff0c;该系列适用于需要高密度安装的应用场合&a…

【git使用】历史commit的分割(git rebase和 git reset的联合使用)

参考 [译] 分割一个已存在的 git commit - 掘金Git - 重写历史idea git如何撤回提交 - PingCodegit 工作原理与撤销操作图解 | Shall We Code? 分割一个已存在的 git commit Git 与其他版本控制系统的主要区别之一&#xff0c;在于其允许用户重写历史。实现这一目的的主要途…

【算法】和为K的连续子数组

牛客链接&#xff1a;https://www.nowcoder.com/practice/704c8388a82e42e58b7f5751ec943a11?tpId196&&tqId37127&rp1&ru/ta/job-code-total&qru/ta/job-code-total/question-ranking 使用【前缀法】&#xff0c;把所有连续和合索引存进哈希表&#xff0c…

2024阿里云服务器可用区选择方法

阿里云服务器地域和可用区怎么选择&#xff1f;地域是指云服务器所在物理数据中心的位置&#xff0c;地域选择就近选择&#xff0c;访客距离地域所在城市越近网络延迟越低&#xff0c;速度就越快&#xff1b;可用区是指同一个地域下&#xff0c;网络和电力相互独立的区域&#…

Dockerfile的EXPOSE

文章目录 环境总结测试使用EXPOSE测试1&#xff1a;不做端口映射测试2&#xff1a;-p 8080:80测试3&#xff1a;-P测试4&#xff1a;--networkhost 不使用EXPOSE 参考 环境 RHEL 9.3Docker Community 24.0.7 总结 如果懒得看测试的详细信息&#xff0c;可以直接看结果&#…

使用is跳转页面的几种方法

1&#xff0c;open() 打开一个新的浏览器窗口 <input type"button" value"去往新窗口按钮" onclick"fun1()">function fun1() {window.open("https://blog.csdn.net/daxiang12092205/article/details/11878477/")} 2&#xff…

二叉树的深度和高度问题(算法村第八关白银挑战)

二叉树的最大深度 104. 二叉树的最大深度 - 力扣&#xff08;LeetCode&#xff09; 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null…

11.perror函数的使用

文章目录 perror函数介绍简介&#xff1a; 测试代码 perror函数介绍 函数原型&#xff1a;void perror(char const *message); 简介&#xff1a; perror函数&#xff0c;以一种简单、统一的方式报告错误。标准库函数在一个外部整型变量errno&#xff08;在errno.h中定义&…

阿里云大数据ACA及ACP复习题(61~80)

61.网络爬虫又称为网络机器人、网络蜘蛛&#xff0c;也可以称它是一种(A)工具 A:从互联网自动提取网页中数据的工具 B:一种病毒软件 C:沉迷于网络有网瘾的人的代称 D:以上都不对 解析&#xff1a;网络爬虫&#xff08;又称为网页蜘蛛&#xff0c;网络机器人&#xff0c;在FOAF社…

JavaWeb——后端案例

五、案例 1. 开发规范—Restful REST&#xff08;Representational State Transfer&#xff09;&#xff0c;表述性状态转换&#xff0c;是一种软件架构风格 注&#xff1a; REST是风格&#xff0c;是约定方式&#xff0c;不是规定&#xff0c;可以打破描述模块的功能通常使…

RA4000CE (RTC模块)适用于汽车,工作温度范围宽,稳定性高

RA4000CE是一个集成了32.768 kHz数字温度补偿晶体振荡器(DTCXO)的RTC模块&#xff0c;适用于汽车&#xff0c;工作温度范围宽&#xff0c;稳定性高。它包括各种功能&#xff0c;如具有闰年校正的秒到年时钟/日历&#xff0c;时间警报&#xff0c;唤醒计时器&#xff0c;时间更新…