Issue
I invoked getpid() in a program for many times (to test the efficiency of system calls), however when I use strace
to get the trace, only one getpid() call is captured.
The code is simple:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void print_usage(){
printf("Usage: program count\n");
exit(-1);
}
int main(int argc, char** argv){
if(argc != 2)
print_usage();
int cnt = atoi(argv[1]);
int i = 0;
while(i++<cnt)
getpid();
return 0;
}
I used gdb
and got this:
(gdb) disasse
Dump of assembler code for function getpid:
0xb76faac0 <getpid+0>: mov %gs:0x4c,%edx
0xb76faac7 <getpid+7>: cmp $0x0,%edx
0xb76faaca <getpid+10>: mov %edx,%eax
0xb76faacc <getpid+12>: jle 0xb76faad0 <getpid+16>
0xb76faace <getpid+14>: repz ret
0xb76faad0 <getpid+16>: jne 0xb76faadc <getpid+28>
0xb76faad2 <getpid+18>: mov %gs:0x48,%eax
0xb76faad8 <getpid+24>: test %eax,%eax
0xb76faada <getpid+26>: jne 0xb76faace <getpid+14>
0xb76faadc <getpid+28>: mov $0x14,%eax
0xb76faae1 <getpid+33>: call *%gs:0x10
0xb76faae8 <getpid+40>: test %edx,%edx
0xb76faaea <getpid+42>: mov %eax,%ecx
0xb76faaec <getpid+44>: jne 0xb76faace <getpid+14>
0xb76faaee <getpid+46>: mov %ecx,%gs:0x48
0xb76faaf5 <getpid+53>: ret
I don't quite understand the assembly code. It would also be helpful if somebody can give some detailed explanation about it. According to my observation, "call *%gs:0x10" (, which jumps into vdso) is not executed, except for the first getpid() call, that may be the reason why subsequent getpid() calls are not captured. But I don't know why.
The linux kernel: 2.6.24-29 gcc (GCC) 4.2.4 libc 2.7,
Thanks!
Solution
Glibc caches the result, since it can't change between calls. See the source code here for instance.
So the real syscall only gets executed once. The other calls just read from the cache. (The code is not very simple because it takes care of doing the Right Thing with threads.)
Answered By - Mat Answer Checked By - Marilyn (WPSolving Volunteer)