关于 gettimeofday 是否真的不涉及到系统调用进行记录
关于 gettimeofday 是否真的不涉及到系统调用进行记录
在《Linux多线程服务端编程》一书 5.1 节中提到过,在 x86-64 的 Linux 上,gettimeofday
不是系统调用,不会陷入内核。其实我是对这句话存有疑问的。众所周知想要获得准确的当前时间,就必须要通过内核的全局的计时变量(ticks 或者 jiffies),但是用 strace 查看调用了 gettimeofday
的进程,发现的确没有涉及到系统调用,没有陷入内核。这就奇了怪了,故上网查找,得到以下信息:
首先, gettimeofday
的确是一个系统调用,因为它所需求的数据是内核所持有的,但它没有走传统的 trap 这条路进入内核,而是利用了 linux 的 vdso(virtual dynamic shared object)机制帮我们做到了在调用这个系统调用时不陷入内核,从而提高了性能。
这个实现方法其实也是很直觉的(intuitive),在程序装载阶段,装载程序观察到程序有需要 vdso 的相关系统调用,就为其做一下内存映射(将对应的系统调用处理函数所需的指令和数据映射到用户空间中去)。那么用户在调用这些函数时自然就不需要陷入内核啦~~
如何调用到这些代码呢?直接调用这些系统调用对应的 glibc 包装函数就可以,因为这些 glibc 包装函数默认会使用 vdso。如果你执意通过 syscall
函数/ syscall
指令/int 0x80
来调用这些系统调用,vdso 是无法生效的,还是会陷入内核。
当然 vdso 也不保证一定不会陷入内核,有些情况下是会 fallback 的,以 clock_gettime
为例,下面是 linux 4.16 版本中该系统调用在 vdso 中的实现:
1 | notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts) |
其中do_realtime
和do_monotonic
如果返回值为VCLOCK_NONE
的话,就会调用vdso_fallback_gettime
,而这个函数是会陷入内核的。另外,clock_gettime
的clock
参数可不止上面代码中switch里面的4个case,如果我们传入的是CLOCK_BOOTTIME
/CLOCK_PROCESS_CPUTIME_ID
/CLOCK_THREAD_CPUTIME_ID
的话,就会走到default分支,还是会调用vdso_fallback_gettime
陷入内核。
综上所诉,gettimeofday
和clock_gettime
实际上都是系统调用,但是调用得当的话,可以避免陷入内核,从而提高性能。是否陷入了内核,可以利用 strace 来判断。