c - 为什么 fseek 使用 read() 系统调用?

标签 c linux system-calls libc

我正在尝试理解 fseek 的 glibc 实现。为此,我下载了 glibc 源代码并尝试了解其函数执行顺序。

我在libio/fseek.c中找到了fseek实现。基本上,它使用相同的参数调用函数(或者更确切地说是宏)_IO_fseek()。该宏在libio/iolibio.h中实现。

它被定义为_IO_seekoff_unlocked (__fp, __offset, __whence, _IOS_INPUT|_IOS_OUTPUT)(在libio/ioseekoff.c中实现)。其执行的下一步对我来说相当困惑:

_IO_seekoff_unlocked 基本上返回 _IO_SEEKOFF (fp, offset, dir, mode);,它返回 _IO_seekoff_unlocked (fp, offset, dir, mode);,这应该创建一个调用循环。

此外,在示例程序 (seek.c) 上使用 strace 时:

#include <stdio.h>

int main(void) {
    printf("[Fseek] Executing fseek\n");
    FILE *f = fopen("./seek.c", "rb");

    fseek(f, 0L, SEEK_END);
}

它表明 fseek 将调用 read 系统调用,即使我在 glibc 实现中找不到它。

...
write(1, "[Fseek] Executing fseek\n", 24[Fseek] Executing fseek
) = 24
openat(AT_FDCWD, "./seek.c", O_RDONLY)  = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=146, ...}) = 0
fstat(3, {st_mode=S_IFREG|0644, st_size=146, ...}) = 0
lseek(3, 0, SEEK_SET)                   = 0
read(3, "#include <stdio.h>\n\nint main(voi"..., 146) = 146
exit_group(0)                           = ?
+++ exited with 0 +++

我的目标是了解这里如何使用 read 系统调用。我有自己的 read 系统调用实现,它适用于我编写的其他测试,但在通过 fseek 调用时会因某种原因失败。

作为示例,我在函数中使用 fseek 来获取文件的大小:

long get_file_size(const char *name)
{
    FILE *temp_file = fopen(name, "rb");
    if (temp_file == NULL)
    {
        return -1;
    }

    fseek(temp_file, 0L, SEEK_END);
    long sz =  ftell(temp_file);
    fclose(temp_file);
    return sz;
}

此函数将使用“正常”read 实现返回正确的大小,但我的会失败。因此,如果有人能告诉我如何理解 fseekread 的使用(我在源代码中找不到),我将非常感激。

最佳答案

_IO_seekoff_unlocked->_IO_SEEKOFF实际上扩展到 JUMP3 (__seekoff, FP, OFF, DIR, MODE)JUMP3是一个从 FILE "jump" table/vtable 调用 __seekoff 的宏.

fopen默认分配 _IO_file_jumps (或类似的东西,因为文件可以进行 mmap 等)作为新 FILE 的跳转表。它是FILE的跳转表/虚拟表的实现。

因此 _IO_SEEKOFF 调用 _IO_file_jumps->__seekoff 。它指向 _IO_new_file_seekoff最后在该函数内调用 _IO_SYSREAD_IO_SYSREAD从跳转表调用 _read,跳转表又调用 _IO_file_read ,它调用 __read最终执行 SYSCALL_CANCEL (read) .

关于c - 为什么 fseek 使用 read() 系统调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58952893/

相关文章:

linux - 如何在每个父目录中打印最后一个目录

sql-server - 从虚拟机访问主机网络上的 SQL Server

c - stat st_mode 始终等于 16877

c - 在c中使用 mkdir -p 创建文件的父文件夹

c - 当您在 C 中将 char * 地址转换为 int * 时,如果地址不是字对齐的,会发生什么情况?

linux - 为什么我们需要为守护进程创建一个新 session ?

c - 我的系统调用无法正常工作

operating-system - 可执行文件的指令去哪儿了?

c - 通过 FIFO 传递结构

c - fork() 调用打印次数超出预期