当我运行命令 cat /proc/cpuinfo 时会发生什么?

slm*_*slm 90 filesystems kernel proc

我写的时候会发生什么cat /proc/cpuinfo。这是通向操作系统的命名管道(或其他东西),它会动态读取 CPU 信息并在我每次调用它时生成该文本?

Gil*_*il' 77

每当您读取 下的文件时/proc,这都会调用内核中的一些代码,该代码计算要读取的文本作为文件内容。内容是动态生成的,这一事实解释了为什么几乎所有文件的时间都报告为现在,大小报告为 0 — 在这里,您应该将 0 读为“不知道”。与通常的文件系统不同,挂载在 上的文件系统/proc称为procfs,它不会从磁盘或其他存储介质(如 FAT、ext2、zfs 等)或通过网络(如 NFS、Samba 等)加载数据并且不调用用户代码(与FUSE不同)。

Procfs 存在于大多数非 BSD unice 中。它在UNIX 第 8 版中的 AT&T 贝尔实验室开始,作为一种报告进程信息的方式(并且ps通常是用于阅读信息的漂亮打印机/proc)。大多数 procfs 实现都有一个文件或目录,/proc/123用于报告有关 PID 为 123 的进程的信息。Linux 使用更多报告系统状态的条目扩展了 proc 文件系统,包括您的示例/proc/cpuinfo

过去,Linux/proc获取了提供有关驱动程序信息的各种文件,但现在不赞成使用这种用法/sys,而/proc现在发展缓慢。为了向后兼容,条目 like/proc/bus/proc/fs/ext4保持在原处,但在/sys. 在这个答案中,我将专注于 Linux。

/proc关于 Linux文档的第一个和第二个入口点是:

  1. proc(5)手册页;
  2. /proc文件系统中的内核文档

您的第三个切入点是在文档未涵盖的情况下阅读源代码。您可以在您的机器上下载源代码,但这是一个巨大的程序,Linux 交叉引用LXR是一个很大的帮助。(LXR 有很多变体;目前运行lxr.linux.no的那个是最好的,但不幸的是该站点经常停机。)需要一点 C 知识,但您不需要成为一名程序员来追踪一个神秘的值.

/proc条目的核心处理在fs/proc目录中。任何驱动程序都可以在 中注册条目/proc(尽管如上所述,现在不推荐使用/sys),因此如果您在 中找不到您要查找的内容fs/proc,请查看其他地方。驱动程序调用在include/linux/proc_fs.h. 高达 3.9 的内核版本提供了函数create_proc_entry和一些包装器(尤其是create_proc_read_entry),而内核版本3.10 及更高版本仅提供proc_createproc_create_data(以及更多)。

/proc/cpuinfo作为一个例子,一个搜索"cpuinfo"带您到呼叫proc_create("cpuinfo, …")fs/proc/cpuinfo.c。您可以看到该代码几乎是样板代码:由于大多数文件/proc只是转储一些文本数据,因此有帮助函数可以做到这一点。只有一个seq_operations结构,真正的肉在cpuinfo_op数据结构中,它依赖于体系结构,通常定义在arch/<architecture>/kernel/setup.c(或有时是不同的文件)中。以 x86 为例,我们被引导到arch/x86/kernel/cpu/proc.c. 那里的主要功能是show_cpuinfo, 打印出所需的文件内容;基础设施的其余部分以它请求的速度将数据提供给读取过程。您可以看到从内核中各种变量中的数据动态组合的数据,包括一些动态计算的数字,例如CPU 频率

其中很大一部分/proc/proc/<PID>. 这些条目注册在fs/proc/base.c,tgid_base_stuff数组中;这里注册的一些函数在其他文件中定义。让我们看几个关于如何生成这些条目的示例:

的另一个重要领域/proc/proc/sys,它是到sysctl. 从此层次结构中的条目读取返回相应 sysctl 值的值,而写入设置 sysctl 值。sysctl 的入口点在fs/proc/proc_sysctl.c. sysctls 有自己的注册系统register_sysctl和朋友。


slm*_*slm 61

在尝试深入了解幕后发生的魔法类型时,您最好的朋友是strace。学习操作这个工具是你可以做的最好的事情之一,以便更好地了解幕后发生的疯狂魔法。

$ strace -s 200 -m strace.log cat /proc/cpuinfo
...
read(3, "processor\t: 0\nvendor_id\t: GenuineIntel\ncpu family\t: 6\nmodel\t\t: 37\nmodel name\t: Intel(R) Core(TM) i5 CPU       M 560  @ 2.67GHz\nstepping\t: 5\nmicrocode\t: 0x4\ncpu MHz\t\t: 1199.000\ncache size\t: 3072 KB\nphy"..., 65536) = 3464
write(1, "processor\t: 0\nvendor_id\t: GenuineIntel\ncpu family\t: 6\nmodel\t\t: 37\nmodel name\t: Intel(R) Core(TM) i5 CPU       M 560  @ 2.67GHz\nstepping\t: 5\nmicrocode\t: 0x4\ncpu MHz\t\t: 1199.000\ncache size\t: 3072 KB\nphy"..., 3464) = 3464
read(3, "", 65536)                      = 0
close(3)                                = 0
...
Run Code Online (Sandbox Code Playgroud)

从上面的输出中你可以看到这/proc/cpuinfo只是一个普通文件,或者至少看起来是一个。所以让我们深入挖掘。

更深的潜水

#1 - 与 ls ..

查看文件本身,它似乎“只是一个文件”。

$ ls -l /proc/cpuinfo 
-r--r--r--. 1 root root 0 Mar 26 22:45 /proc/cpuinfo
Run Code Online (Sandbox Code Playgroud)

但仔细看看。我们得到第一个提示,它的特殊性,注意文件的大小是 0 字节。

#2 - 与统计..

如果我们现在查看文件,stat我们可以得到下一个提示,即/proc/cpuinfo.

运行 #1
$ stat /proc/cpuinfo 
  File: ‘/proc/cpuinfo’
  Size: 0           Blocks: 0          IO Block: 1024   regular empty file
Device: 3h/3dInode: 4026532023  Links: 1
Access: (0444/-r--r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Context: system_u:object_r:proc_t:s0
Access: 2014-03-26 22:46:18.390753719 -0400
Modify: 2014-03-26 22:46:18.390753719 -0400
Change: 2014-03-26 22:46:18.390753719 -0400
 Birth: -
Run Code Online (Sandbox Code Playgroud) 运行 #2
$ stat /proc/cpuinfo 
  File: ‘/proc/cpuinfo’
  Size: 0           Blocks: 0          IO Block: 1024   regular empty file
Device: 3h/3dInode: 4026532023  Links: 1
Access: (0444/-r--r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Context: system_u:object_r:proc_t:s0
Access: 2014-03-26 22:46:19.945753704 -0400
Modify: 2014-03-26 22:46:19.945753704 -0400
Change: 2014-03-26 22:46:19.945753704 -0400
 Birth: -
Run Code Online (Sandbox Code Playgroud)

注意访问、修改和更改时间?它们会随着每次访问而不断变化。这是非常不寻常的,所有 3 都会发生这样的变化。除非编辑,否则文件的时间戳属性通常保持不变。

#3 - 与文件..

另一个线索表明这个文件不是一个普通文件:

$ file /proc/cpuinfo 
/proc/cpuinfo: empty
Run Code Online (Sandbox Code Playgroud)

如果它是命名管道的某种表现形式,它将显示类似于以下文件之一:

$ ls -l /dev/initctl /dev/zero 
prw-------. 1 root root    0 Mar 26 20:09 /dev/initctl
crw-rw-rw-. 1 root root 1, 5 Mar 27 00:39 /dev/zero

$ file /dev/initctl /dev/zero 
/dev/initctl: fifo (named pipe)
/dev/zero:    character special
Run Code Online (Sandbox Code Playgroud)

如果我们触摸emptyfile,/proc/cpuinfo看起来更像是一个文件而不是一个管道:

$ touch emptyfile
$ ls -l emptyfile 
-rw-rw-r--. 1 saml saml 0 Mar 27 07:40 emptyfile
$ file emptyfile 
emptyfile: empty
Run Code Online (Sandbox Code Playgroud) #4 - 安装..

所以在这一点上,我们需要退后一步并缩小一点。我们正在查看一个特定的文件,但也许我们应该查看该文件所在的文件系统。为此,我们可以使用mount命令。

$ mount | grep " /proc "
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
Run Code Online (Sandbox Code Playgroud)

好的,所以文件系统类型的类型是proc。所以/proc是不同的文件系统类型,这就是我们的暗示下的文件/proc是特殊的。它们不仅仅是您运行的工厂文件。因此,让我们找出更多有关是什么使proc文件系统特殊之处的。

看一下mount的手册页:

proc 文件系统不与特殊设备相关联,并且在安装它时,可以使用任意关键字,例如 proc 代替设备规范。(习惯上的选择 none 不太幸运:来自 umount 的错误消息“none busy”可能会令人困惑。)

如果我们看一下proc的手册页:

proc 文件系统是一个伪文件系统,用作内核数据结构的接口。它通常安装在 /proc。其中大部分是只读的,但有些文件允许更改内核变量。

在同一个手册页中再往下一点:

/proc/cpuinfo

这是 CPU 和系统架构相关项的集合,对于每个支持的架构都有不同的列表。两个常见的条目是处理器,它给出了 CPU 编号和 bogomips;在内核初始化期间计算的系统常数。SMP 机器具有每个 CPU 的信息。lscpu(1) 命令从此文件中收集其信息。

在手册页的底部是对内核文档的引用,您可以在此处找到该文档,标题为:THE /proc FILESYSTEM。引用该文件:

proc 文件系统充当内核中内部数据结构的接口。它可用于获取有关系统的信息并在运行时更改某些内核参数 (sysctl)。

结论

那么我们在这里学到了什么?考虑到它/proc被称为伪文件系统和“内部数据结构的接口”,假设其中的项目不是实际文件,而只是看起来像文件的表现形式,但实际上不是。

我将以这句引言结束,它显然曾经出现在man 5 proc大约 2004 年的先前版本中, 但无论出于何种原因不再包含在内。注意:我不知道为什么它被删除了,因为它很好地描述了什么/proc是:

GNU/Linux 系统上的 /proc 目录为内核提供了一个类似文件系统的接口。这允许应用程序和用户使用正常的文件系统 I/O 操作从内核中获取信息和设置值。

proc 文件系统有时被称为进程信息伪文件系统。它不包含“真实”文件,而是包含运行时系统信息(例如系统内存、安装的设备、硬件配置等)。因此,它可以被视为内核的控制和信息中心。事实上,相当多的系统实用程序只是调用此目录中的文件。例如,列出内核加载的模块的命令lsmod与'cat /proc/modules'基本相同,而列出连接到系统PCI总线的设备的lspci与'cat /过程/ pci'。通过更改位于此目录中的文件,您可以在系统运行时更改内核参数。

来源: proc 伪文件系统

参考

  • 不错的答案!在 linux 上,如果您想深入挖掘,proc 文件系统的源代码位于内核源代码中的 fs/proc 中。你会看到有一个 fs/proc/cpuinfo.c,但不幸的是,它相当空,因为繁重的工作分散在 arch/ 上,因为它依赖于体系结构。有关更简单的示例,请参阅 fs/proc/uptime.c。通过查看文件,我们可以猜测 uptime_proc_show 是获取我们想要的数据的主力,我们可以通过深入研究它调用的函数来进一步探索它。要了解 seq_file 接口及其在 procfs 中的使用方式,请参阅: (2认同)
  • @slm:+1,很好的答案。但是对我来说,第一个提示它是一个特殊文件是它的大小 ^^ 0 字节,但是你可以从中获取很多东西(有点像一些管道文件)。 (2认同)

War*_*rbo 15

@slm 给出的答案非常全面,但我认为更简单的解释可能来自视角的变化。

在日常使用中,我们可以将文件视为物理事物,即。存储在某个设备上的数据块。这使得像 /proc/cpuinfo 这样的文件非常神秘和混乱。但是,如果我们将文件视为一个界面,这一切都非常有意义;一种将数据传入和传出某个程序的方法。

以这种方式发送和接收数据的程序是文件系统或驱动程序(取决于您如何定义这些术语,定义可能太宽泛或太窄)。重要的一点是,其中一些程序使用硬件设备来存储和检索通过此接口发送的数据;但不是所有的。

使用存储设备(至少不直接使用)的文件系统的一些示例是:

  • 使用查找或计算数据的文件系统。Proc 就是一个例子,因为它从各种内核模块中获取数据。一个极端的例子是 ?fs ( github.com/philipl/pifs )
  • 所有 FUSE 文件系统,使用常规用户空间程序处理数据
  • 即时转换另一个文件系统数据的文件系统,例如使用加密、压缩甚至音频转码 ( khenriks.github.io/mp3fs/ )

Plan9 OS ( http://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs ) 是使用文件作为通用编程接口的极端示例。