问题
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.
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
.
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
basically returns _IO_SEEKOFF (fp, offset, dir, mode);
, which returns _IO_seekoff_unlocked (fp, offset, dir, mode);
, which should create a call loop.
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);
}
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 +++
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
.
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;
}
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.
回答1:
_IO_seekoff_unlocked->_IO_SEEKOFF actually expands to JUMP3 (__seekoff, FP, OFF, DIR, MODE). JUMP3 is a macro that calls __seekoff
from the FILE
"jump" table/vtable.
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
.
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).
来源:https://stackoverflow.com/questions/58952893/why-does-fseek-use-read-system-call