![](/img/trans.png)
[英]Why is the time reported by time() sometimes 1 second behind the seconds component of timespec_get() in C code?
[英]Where to find the source code of timespec_get?
C11
标准提供了功能timespec_get
。 如果我在cppreference或我的计算机上运行示例代码,则可以运行:
#include <stdio.h>
#include <time.h>
int main(void)
{
struct timespec ts;
timespec_get(&ts, TIME_UTC);
char buff[100];
strftime(buff, sizeof buff, "%D %T", gmtime(&ts.tv_sec));
printf("Current time: %s.%09ld UTC\n", buff, ts.tv_nsec);
}
但是,如果我在这里查看glibc的源代码,则代码如下:
#include <time.h>
/* Set TS to calendar time based in time base BASE. */
int
timespec_get (struct timespec *ts, int base)
{
switch (base)
{
case TIME_UTC:
/* Not supported. */
return 0;
default:
return 0;
}
return base;
}
stub_warning (timespec_get)
哪个...不行...
这就引出了一个问题: timespec_get
的源代码实际在哪里?
timespec_get
函数的实现取决于运行库的系统,因此它既显示为time/timespec_get.c
的存根(如果没有可用的实现),也显示为其他地方的各种与系统相关的实现。
您可以在sysdeps/unix/sysv/linux/timespec_get.c
看到Linux的实现,
/* Set TS to calendar time based in time base BASE. */
int
timespec_get (struct timespec *ts, int base)
{
switch (base)
{
int res;
INTERNAL_SYSCALL_DECL (err);
case TIME_UTC:
res = INTERNAL_VSYSCALL (clock_gettime, err, 2, CLOCK_REALTIME, ts);
if (INTERNAL_SYSCALL_ERROR_P (res, err))
return 0;
break;
default:
return 0;
}
return base;
}
这只是围绕vDSO调用的一个精简包装,而vDSO是Linux内核本身的一部分。 如果您感到好奇,请在此处查找clock_gettime
的定义。 vDSO中存在clock_gettime
是不寻常的,这种方式仅实现了少量系统调用。
这是在arch/x86/entry/vdso/vclock_gettime.c
找到的CLOCK_REALTIME
的x86实现:
/* Code size doesn't matter (vdso is 4k anyway) and this is faster. */
notrace static int __always_inline do_realtime(struct timespec *ts)
{
unsigned long seq;
u64 ns;
int mode;
do {
seq = gtod_read_begin(gtod);
mode = gtod->vclock_mode;
ts->tv_sec = gtod->wall_time_sec;
ns = gtod->wall_time_snsec;
ns += vgetsns(&mode);
ns >>= gtod->shift;
} while (unlikely(gtod_read_retry(gtod, seq)));
ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
ts->tv_nsec = ns;
return mode;
}
基本上,您的进程中有一些内存由内核更新,而您的CPU中有一些寄存器可以跟踪时间的流逝(或虚拟机管理程序提供的内存)。 您进程中的内存用于将这些CPU寄存器的值转换为挂钟时间。 您必须循环阅读这些内容,因为在阅读它们时它们可能会发生变化...循环逻辑会在读取错误时检测到这种情况,然后重试。
链接到的timespec_get
定义是一个存根(请参阅stub_warning
)。 实际的实现将在您平台的sysdeps
下进行。 例如,这是sysv
的版本: https : //github.com/lattera/glibc/blob/a2f34833b1042d5d8eeb263b4cf4caaea138c4ad/sysdeps/unix/sysv/linux/timespec_get.c
int timespec_get (ts, base)
struct timespec *ts;
int base;
{
switch (base)
{
int res;
INTERNAL_SYSCALL_DECL (err);
case TIME_UTC:
res = INTERNAL_GETTIME (CLOCK_REALTIME, ts);
if (INTERNAL_SYSCALL_ERROR_P (res, err))
return 0;
break;
default:
return 0;
}
return base;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.