为什么fseek使用read()系统调用? [英] Why does fseek use read() system call?
问题描述
我试图了解fseek
的glibc实现.为此,我下载了glibc源代码并尝试了解其功能执行顺序.
I'm trying to understand the glibc implementation of fseek
. To do so, I downloaded the glibc source code and tried to understand its function execution order.
我在libio/fseek.c
中找到了fseek
实现.基本上,它使用相同的参数调用函数(或宏)_IO_fseek()
.此宏在libio/iolibio.h
中实现.
I found the fseek
implementation in libio/fseek.c
. Basically, it calls the function (or rather the macro) _IO_fseek()
using the same parameters. This macro is implemented in libio/iolibio.h
.
它定义为_IO_seekoff_unlocked (__fp, __offset, __whence, _IOS_INPUT|_IOS_OUTPUT)
(在libio/ioseekoff.c
中实现).执行此操作的下一步对我来说很令人困惑:
It is defined as _IO_seekoff_unlocked (__fp, __offset, __whence, _IOS_INPUT|_IOS_OUTPUT)
(implemented in libio/ioseekoff.c
). The next step in its execution is rather confusing for me:
_IO_seekoff_unlocked
基本上返回_IO_SEEKOFF (fp, offset, dir, mode);
,它返回_IO_seekoff_unlocked (fp, offset, dir, mode);
,这应该创建一个调用循环.
_IO_seekoff_unlocked
basically returns _IO_SEEKOFF (fp, offset, dir, mode);
, which returns _IO_seekoff_unlocked (fp, offset, dir, mode);
, which should create a call loop.
此外,在示例程序(seek.c
)上使用strace
时:
Also, when using strace
on an example program (seek.c
):
#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实现中找不到它.
it shows that fseek
will call the read
system call, even though I could not find it in the glibc implementation.
...
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
系统调用实现,对于我编写的其他测试来说效果很好,但是通过fseek
调用时由于某些原因会失败.
My goal is to understand how the read system call is used here. I have my own implementation of the read
system call, which works well for other tests I wrote but will fail for some reason when it is called via fseek
.
作为示例,我在函数中使用fseek
来获取文件的大小:
As an example, I use fseek
in a function to get the size of a file:
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
实现返回正确的大小,但由于我的原因将失败.因此,如果有人能告诉我如何理解fseek
中read
的用法(我在源代码中找不到),我将不胜感激.
This function will return the correct size with the "normal" read
implementation but will fail with mine. So, if anybody can tell me how I can understand the use of read
within fseek
(which I could not find in the source), I would highly appreciate it.
推荐答案
JUMP3 (__seekoff, FP, OFF, DIR, MODE)
. JUMP3
是调用FILE
跳转"表/vtable .
打开默认情况下分配 _IO_file_jumps
(或者类似的东西,因为文件可以被映射等)作为新FILE
的跳转表.它是FILE
的跳转表/虚拟表的实现.
fopen by default assigns _IO_file_jumps
(or something like that, because the file can be mmap-ed etc. etc.) as the jump table for new FILE
s. It is the implementation of the jump table/virtual table for a FILE
.
因此_IO_SEEKOFF
调用 _IO_file_jumps->__seekoff
.它指向 _IO_new_file_seekoff
,最后在其中函数会调用 _IO_SYSREAD
. _IO_SYSREAD
从跳转表,依次调用 _IO_file_read
,它调用 __read
最终执行
So _IO_SEEKOFF
calls _IO_file_jumps->__seekoff
. It points to _IO_new_file_seekoff
and finally inside that function a call is made to _IO_SYSREAD
. _IO_SYSREAD
calls _read
from the jump table, which in turn calls _IO_file_read
, which calls __read
which finally executes SYSCALL_CANCEL (read)
.
这篇关于为什么fseek使用read()系统调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!