记一次简单strace cat
命令行输入如下
touch foo
echo hello > foo
strace cat foo
出现以下信息
...
openat(AT_FDCWD, "foo", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=6, ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
mmap(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc2b662b000
read(3, "Hello\n", 131072) = 6
write(1, "Hello\n", 6Hello
) = 6
read(3, "", 131072) = 0
munmap(0x7fc2b662b000, 139264) = 0
...
省略了部分打开一些链接库的系统调用,以下逐行分析
openat
始于版本 2.6.16,Linux 内核提供了一系列新的系统调用,在执行与传统系统调用相似任务的 同时,还提供了一些附加功能。
openat就是在open的基础上,来确认对传入的pathname解释,第一个参数传入特殊AT_FDCWD,对其解释同进程工作目录一样,so和open没啥区别。
fstat
返回某个文件描述符的指代文件的相关信息,即{st_mode=S_IFREG|0644, st_size=6, ...}
,此时用的是描述符3,即刚刚用openat打开的foo文件。
fadvise
此系统调用允许进程就自身访问文件数据时可能采取的模式通知内核,内核可以(但不必非要)根据 posix_fadvise()所提供的信息来优化对缓冲区高速缓存的使 用,进而提高进程和整个系统的性能。调用 posix_fadvise()对程序语义并无影响。
这里使用的flag为POSIX_FADV_SEQUENTIAL
,表示进程预计会从低偏移量到高偏移量顺序读取数据。
mmap
此在调用进程的虚拟地址空间中创建一个新映射。
这里的addr选择为null值,系统内核会为映射 选择一个合适的地址。这是创建映射的首选做法。
PROT_READ|PROT_WRITE
此prot表示映射区域可读可写。
MAP_PRIVATE|MAP_ANONYMOUS
这里比较特殊,即是一个匿名映射也是私有映射,这是用来分配内存的,后续的fd也就传了无用的-1。
因此,这个mmap用来申请新的内存。
read
打开fd,读取文件数据,从3(文件foo)中读取数据,读入缓冲区(刚刚申请的内存)。
再次调用read,发现已读完,因此关闭了此fd。
write
将刚刚读到的数据,写入标准输出(为了在终端上显示),完成了从foo到终端(3 -> 1)。
munmap
与mmap相反,将调用进程的虚拟地址空间的映射删除。