代码之家  ›  专栏  ›  技术社区  ›  Vincent

在哪里可以找到timespec-get的源代码?

  •  0
  • Vincent  · 技术社区  · 8 年前

    这个 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的来源 here ,代码如下:

    #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获取 那是真的吗?

    2 回复  |  直到 8 年前
        1
  •  4
  •   Dietrich Epp    8 年前

    这个 timespec_get 函数的实现依赖于运行库的系统,因此它看起来都是一个存根。 time/timespec_get.c (如果没有可用的实现)以及其他各种与系统相关的实现。

    您可以在中看到Linux实现 sysdeps/unix/sysv/linux/timespec_get.c ,

    /* 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中,只有少数syscalls是通过这种方式实现的。

    以下是的x86实现 CLOCK_REALTIME ,在中找到 arch/x86/entry/vdso/vclock_gettime.c :

    /* 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寄存器的值转换为墙壁时钟时间。你必须在一个循环中阅读它们,因为当你阅读它们的时候它们会改变…循环逻辑在读取错误时检测案例,然后重试。

        2
  •  1
  •   Dai    8 年前

    这个 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;
    }