Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何确定linux内核是否会在月底插入闰秒_C_Linux_Time - Fatal编程技术网

C 如何确定linux内核是否会在月底插入闰秒

C 如何确定linux内核是否会在月底插入闰秒,c,linux,time,C,Linux,Time,假设我的程序运行在一台linux机器上,该机器已正确配置为处理。如何准确地完成配置(NTP,配置文件)不应该与此问题相关 实际上,内核将在UTC月末插入额外的一秒或跳过一秒。这会影响gettimeofday(2)读取的时间值。每月的最后一个UTC秒重复或跳过。闰秒期间的时间读数示例如下 我的问题是:在C/C++程序中,如何确定闰秒是否会在月底发生,以及在哪个方向发生。那么如何在linux上实现以下功能呢 int leap_seconds_scheduled_for_end_of_month()

假设我的程序运行在一台linux机器上,该机器已正确配置为处理。如何准确地完成配置(NTP,配置文件)不应该与此问题相关

实际上,内核将在UTC月末插入额外的一秒或跳过一秒。这会影响gettimeofday(2)读取的时间值。每月的最后一个UTC秒重复或跳过。闰秒期间的时间读数示例如下

我的问题是:在C/C++程序中,如何确定闰秒是否会在月底发生,以及在哪个方向发生。那么如何在linux上实现以下功能呢

int leap_seconds_scheduled_for_end_of_month() {
  if (/*kernel_will_insert_extra_second?*/)
    return 1;
  if (/*kernel_will_skip_over_last_second?*/)
    return -1;
  return 0;
}
如果结果不正确,如果月底是遥远的未来,这是可以的。(就我而言,远大于等于2秒)答案必须是正确的(*),在可能的闰秒之前的最后一秒,即每月最后一天的23:59:58 UTC。如果我在闰秒发生后才了解它是不够的,因为我必须提前做好准备

我一直试图在sysfs或procfs中找到任何闰秒指示器,但迄今为止都没有成功


(*)当然,如果内核本身在闰秒发生之前只知道一小部分,例如由于NTP服务在整个上个月中断,那么答案就不可能是正确的。没关系。

好吧,内核不会提前通知正在计划的闰秒。此知识由NTP守护进程维护,当需要伪造系统时钟时,
ntpd
发出系统调用以调整系统时钟

要插入您的ntpd守护程序,请执行以下操作:

$ /usr/sbin/ntpq -c 'lassoc' -c "mrv &1 &999 leap,srcadr,stratum"

ind assid status  conf reach auth condition  last_event cnt
===========================================================
  1  5159  80a3   yes    no  none    reject unreachable 10
  2  5160  968a   yes   yes  none  sys.peer    sys_peer  8
srcadr=LOCAL(0), leap=00, stratum=10

srcadr=timeserver.example.com, leap=00, stratum=4
当您看到为leap设置的“01”时,您就有了一个闰秒。对于配置ntp服务器的每个源,“srcadr”行都会重复,因此您可能有多个条目(我的示例返回虚拟本地系统cl)


对于一个C++解决方案,你必须做一个丑陋的叉/执行程序:<代码> /Ur/SbIn/Ntpq,并捕获输出,或者挖Socket协议<代码> NTPQ < /Co> >用它来与NTP守护进程对话,然后自己动手,从守护进程中获取响应。当前(UTC)日结束时的闰秒。如果支持,则在距闰秒不到一天时由ntpd设置

$ ./print_leap 
1435706912.426035 82874.419021628 1  1
[... skipping to the second before the leap second]
1435708798.929115 84760.922063075 1  1
1435708799.013439 84761.006388727 1  1
[... skipping to the leap second]
1435708799.981243 84761.974190967 1  1
1435708799.049374 84762.042323977 3  1
[... skipping to the second after the leap second]
1435708799.913464 84762.906413341 3  1
1435708800.000183 84762.993132942 3  1
1435708800.477323 84763.470272391 4  1
[... skipping to a change in the ntpq reading]
1435708840.094271 84803.087225581 4  1
1435708840.618538 84803.611493081 4  0
[... skipping to the last programmatic reading]
1435708921.042020 84884.034975833 4  0
$ ./print_leap  # manual reading several hours later 
1435724912.944500 100875.937487693 0  0
因此,如果(a)您的ntp守护进程从其源代码处得到通知,并且(b)您的ntp守护进程正确地确定您的内核支持此标志,那么您基本上可以通过检查此标志获得闰秒的一天警告

我不认为该标志是通过sysfs或procfs公开的;但是,通过adjtimex syscall从C中检索很容易:

#include <sys/timex.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    struct timex buf;
    int res;

    buf.modes = 0;

    res = adjtimex(&buf);
    if(res < 0) {
        perror("Error calling adjtimex");
        return 1;
    }

    printf("clock status: %i\n", res);
    return 0;
}

感谢Sam Varshavchik和richvdh,他们都为这个问题提供了非常有用的答案。昨晚,发生了闰秒,现在我在几台计算机上运行了使用这两种方法的示例读数

为了便于阅读,我将在单独的答案中发布数据,而不是在注释中。以下C程序用于读取时间并确定是否会出现闰秒:

#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <string.h>
#include <sys/timex.h>
#include <unistd.h>

/* This C function implements Sam Varshavchik's method */
int leap_seconds_scheduled_for_end_of_month() {
  char ntpq_output[1024];
  /* The path to ntpq might have to be adjusted for your system */
  FILE * ntpq_stream = popen("/usr/bin/ntpq -c lassoc -c 'mrv &1 &999 leap,srcadr,stratum'","r");
  memset(ntpq_output,0,1024);
  fread(ntpq_output,1,1022,ntpq_stream);
  pclose(ntpq_stream);
  /* This finds the first leap=xx occurrence in ntpq's output. If 
     multiple upstream ntp servers are configured, there will be one
     line of text for each of them. It would be good to check that
     the stratum=xx value in the same line is not 16 (which means
     invalid). If it is, better use the leap=xx value from another 
     output line. Not done here for simplicity. */ 
  char * leap_bits = strstr(ntpq_output,"leap=");
  if (leap_bits == NULL)
    return 0;
  leap_bits += 5;
  if (leap_bits[0] == '0' && leap_bits[1] == '1')
    return 1;
  if (leap_bits[0] == '1' && leap_bits[1] == '0')
    return -1;
  return 0;
}

/* This function prints the following data in a single line of text:
   gettimeofday, clock_gettime for CLOCK_MONOTONIC, adjtimex (richvdh's
   solution), and Sam's solution */
print_current_data() {
  struct timeval tv = {0,0};
  gettimeofday(&tv,NULL);
  printf("%u.%06u ", (unsigned)tv.tv_sec, (unsigned)tv.tv_usec);

  struct timespec ts = {0,0};
  clock_gettime(CLOCK_MONOTONIC, &ts);
  printf("%u.%09u ", (unsigned)ts.tv_sec, (unsigned)ts.tv_nsec);

  struct timex buf;
  buf.modes = 0;
  printf("%d ", adjtimex(&buf));

  printf("%2d\n", leap_seconds_scheduled_for_end_of_month());
}

/* main just calls print_current_data repeatedly. 
   If we are far away from the leap second, it sleeps between 
   printouts to reduce the ammount of data. */ 
int main(int argc, char ** argv) {
  /* this is the time_t value for the second after the 2015 leap second */
  time_t post_leap = 1435708800;
  for(;;) {
    time_t now = time(NULL);
    print_current_data();
    if (now < (post_leap-60)) {
      sleep(30);
    } else if (now < (post_leap - 10)) {
      sleep(5);
    } else if (now < (post_leap - 2)) {
      usleep(500000);
    } else if (now <= (post_leap + 1)) {
    } else if (now > (post_leap + 120)) {
      return 0;
    } else if (now > (post_leap + 1)) {
      usleep(500000);
    }
  }

  return 0;
}
在闰秒后大约4.5小时的手动检查中,Sam的方法也回到了0

系统2:Cubieboard 2运行Debian 8,内核为3.4.107-cubietruck ntp包的版本为1:4.2.6.p5+dfsg-7

$ ./print_leap
1435703847.373559 948687.514617591 1  1
[... skipping to the second before the leap second]
1435708798.998980 953639.139771365 1  1
1435708799.028375 953639.169165960 1  1
[... skipping to the leap second]
1435708799.986449 953640.127238940 1  1
1435708799.020017 953640.160809364 3  1
[... skipping to the second after the leap second]
1435708799.984912 953641.125702281 3  1
1435708800.012875 953641.153666113 4  1
[... skipping to the last programmatic reading]
1435708921.268660 953762.409472677 4  1
$ ./print_leap  # manual reading several hours later
1435725362.080253 970203.221195342 0  0
系统3:Raspberrypi model B运行内核为3.12.35的Raspbian 7+ ntp包的版本为1:4.2.6.p5+dfsg-2+deb7u1

$ ./print_leap 
1435704085.032222 313606.064883453 1  1
[... skipping to the second before the leap second]
1435708798.969855 318320.002146274 1  1
1435708799.040573 318320.072865002 1  1
[... skipping to the leap second]
1435708799.996887 318321.029180271 1  1
1435708799.071282 318321.103573880 3  1
[... skipping to the second after the leap second]
1435708799.945609 318321.977898784 3  1
1435708800.017116 318322.049407486 4  1
[... skipping to the last programmatic reading]
1435708921.136882 318443.169189210 4  1
$ ./print_leap  # manual reading several hours later 
1435732962.263988 342484.296617478 0  0
系统4:英特尔NUC DN2820运行Ubuntu 15.04,内核为3.19.0-20-generic ntp包的版本为1:4.2.6.p5+dfsg-3ubuntu6

请注意闰秒开始时的小故障:

nuc@nuc1:~$ ./print_leap 
1435703986.534020 1305198.740735208 1  1
[... skipping to the second before the leap second]
1435708798.991478 1310011.198081950 1  1
1435708799.000905 1310011.207509156 1  1
[... skipping to the leap second]
1435708799.989309 1310012.195913702 1  1
1435708800.000738 1310012.207343097 1  1
1435708799.016079 1310012.222683886 3  1
[... skipping to the second after the leap second]
1435708799.999616 1310013.206220581 3  1
1435708800.012446 1310013.219050861 4  1
[... skipping to the last programmatic reading]
1435708921.047985 1310134.254602197 4  1
nuc@nuc1:~$ ./print_leap  # manual reading several hours later
1435725807.234545 1327020.441295352 0  0
系统5:Intel NUC DN2820运行Ubuntu 14.04,内核为3.13.0-53-generic ntp包的版本为1:4.2.6.p5+dfsg-3ubuntu2.14.04.3

nuc@nuc2:~$ ./print_leap 
1435704031.137881 323125.995674014 1  1
[... skipping to the second before the leap second]
1435708798.995646 327893.853350053 1  1
1435708799.007936 327893.865640804 1  1
[... skipping to the leap second]
1435708799.995589 327894.853293338 1  1
1435708799.007527 327894.865231774 3  1
[... skipping to the second after the leap second]
1435708799.998111 327895.855815619 3  1
1435708800.013461 327895.871165134 4  1
[... skipping to the last programmatic reading]
1435708921.282149 328017.139858311 4  1
nuc@nuc2:~$ ./print_leap  # manual reading several hours later 
1435725557.303859 344653.161689304 0  0
系统6:运行Ubuntu 14.04的联想E330笔记本电脑,内核为3.13.0-55-generic ntp包的版本为1:4.2.6.p5+dfsg-3ubuntu2.14.04.3

nuc@nuc2:~$ ./print_leap 
1435704031.137881 323125.995674014 1  1
[... skipping to the second before the leap second]
1435708798.995646 327893.853350053 1  1
1435708799.007936 327893.865640804 1  1
[... skipping to the leap second]
1435708799.995589 327894.853293338 1  1
1435708799.007527 327894.865231774 3  1
[... skipping to the second after the leap second]
1435708799.998111 327895.855815619 3  1
1435708800.013461 327895.871165134 4  1
[... skipping to the last programmatic reading]
1435708921.282149 328017.139858311 4  1
nuc@nuc2:~$ ./print_leap  # manual reading several hours later 
1435725557.303859 344653.161689304 0  0
请注意闰秒结束后的不一致性

$ ./print_leap 
1435706912.426035 82874.419021628 1  1
[... skipping to the second before the leap second]
1435708798.929115 84760.922063075 1  1
1435708799.013439 84761.006388727 1  1
[... skipping to the leap second]
1435708799.981243 84761.974190967 1  1
1435708799.049374 84762.042323977 3  1
[... skipping to the second after the leap second]
1435708799.913464 84762.906413341 3  1
1435708800.000183 84762.993132942 3  1
1435708800.477323 84763.470272391 4  1
[... skipping to a change in the ntpq reading]
1435708840.094271 84803.087225581 4  1
1435708840.618538 84803.611493081 4  0
[... skipping to the last programmatic reading]
1435708921.042020 84884.034975833 4  0
$ ./print_leap  # manual reading several hours later 
1435724912.944500 100875.937487693 0  0
系统7:装有AMD Phenom CPU的戴尔服务器,运行Ubuntu 14.04,内核为3.13.0-53-generic ntp包的版本为1:4.2.6.p5+dfsg-3ubuntu2.14.04.3

nuc@nuc2:~$ ./print_leap 
1435704031.137881 323125.995674014 1  1
[... skipping to the second before the leap second]
1435708798.995646 327893.853350053 1  1
1435708799.007936 327893.865640804 1  1
[... skipping to the leap second]
1435708799.995589 327894.853293338 1  1
1435708799.007527 327894.865231774 3  1
[... skipping to the second after the leap second]
1435708799.998111 327895.855815619 3  1
1435708800.013461 327895.871165134 4  1
[... skipping to the last programmatic reading]
1435708921.282149 328017.139858311 4  1
nuc@nuc2:~$ ./print_leap  # manual reading several hours later 
1435725557.303859 344653.161689304 0  0
注意闰秒开始和结束时的小故障

$ ./print_leap
1435704125.933343 2210517.393979537 1  1
[... skipping to the second before the leap second]
1435708798.998012 2215190.458598770 1  1
1435708799.002893 2215190.463480413 1  1
[... skipping to the leap second]
1435708799.994690 2215191.455273816 1  1
1435708800.001917 2215191.462501431 1  1
1435708799.013505 2215191.474092236 3  1
[... skipping to the second after the leap second]
1435708799.992212 2215192.452796670 3  1
1435708800.000210 2215192.460794341 3  1
1435708800.006819 2215192.467403224 4  1
[... skipping to the last programmatic reading]
1435708921.323808 2215313.784400730 4  1
$ ./print_leap  # manual reading several hours later
1435726838.319240 2233230.779876616 0  0
System 8:运行Debian 6的虚拟服务器,使用主机内核2.6.32-028stab094.3 来宾系统中未安装ntp程序包。ntp可以在主机上运行,也可以不在主机上运行。主机向来宾系统提供时间。

$ ./print_leap 
sh: /usr/bin/ntpq: No such file or directory
1435704206.353115 114299811.979591258 1  0
[... skipping to the second before the leap second]
sh: /usr/bin/ntpq: No such file or directory
1435708798.994303 114304404.620727643 1  0
sh: /usr/bin/ntpq: No such file or directory
1435708799.000291 114304404.626715249 1  0
[... skipping to the leap second]
sh: /usr/bin/ntpq: No such file or directory
1435708799.999445 114304405.625868168 1  0
sh: /usr/bin/ntpq: No such file or directory
1435708799.004273 114304405.630696209 3  0
[... skipping to the second after the leap second]
sh: /usr/bin/ntpq: No such file or directory
1435708799.998234 114304406.624656721 3  0
sh: /usr/bin/ntpq: No such file or directory
1435708800.003723 114304406.630146580 4  0
[... skipping to the last programmatic reading]
sh: /usr/bin/ntpq: No such file or directory
1435708921.185876 114304527.812316105 4  0
$ ./print_leap  # manual reading several hours later
sh: /usr/bin/ntpq: No such file or directory
1435727243.250130 114322849.876607481 0  0
$ ./print_leap 
sh: 1: /usr/bin/ntpq: not found
1435704263.521402 627240.363389922 1  0
[... skipping to the second before the leap second]
sh: 1: /usr/bin/ntpq: not found
1435708798.991150 631775.833122648 1  0
sh: 1: /usr/bin/ntpq: not found
1435708799.062267 631775.904240598 1  0
[... skipping to the leap second]
sh: 1: /usr/bin/ntpq: not found
1435708799.986215 631776.828187732 1  0
sh: 1: /usr/bin/ntpq: not found
1435708799.061678 631776.903650529 3  0
[... skipping to the second after the leap second]
sh: 1: /usr/bin/ntpq: not found
1435708799.987007 631777.828979335 3  0
sh: 1: /usr/bin/ntpq: not found
1435708800.061094 631777.903067236 4  0
[... skipping to the last programmatic reading]
sh: 1: /usr/bin/ntpq: not found
1435708921.380148 631899.222124765 4  0
$ ./print_leap  # manual reading several hours later
sh: 1: /usr/bin/ntpq: not found
1435727152.545742 650130.387735253 0  0
系统9:运行Debian 8的虚拟服务器,使用主机的内核2.6.32-37-pve 来宾系统中未安装ntp程序包。ntp可以在主机上运行,也可以不在主机上运行。主机向来宾系统提供时间。

$ ./print_leap 
sh: /usr/bin/ntpq: No such file or directory
1435704206.353115 114299811.979591258 1  0
[... skipping to the second before the leap second]
sh: /usr/bin/ntpq: No such file or directory
1435708798.994303 114304404.620727643 1  0
sh: /usr/bin/ntpq: No such file or directory
1435708799.000291 114304404.626715249 1  0
[... skipping to the leap second]
sh: /usr/bin/ntpq: No such file or directory
1435708799.999445 114304405.625868168 1  0
sh: /usr/bin/ntpq: No such file or directory
1435708799.004273 114304405.630696209 3  0
[... skipping to the second after the leap second]
sh: /usr/bin/ntpq: No such file or directory
1435708799.998234 114304406.624656721 3  0
sh: /usr/bin/ntpq: No such file or directory
1435708800.003723 114304406.630146580 4  0
[... skipping to the last programmatic reading]
sh: /usr/bin/ntpq: No such file or directory
1435708921.185876 114304527.812316105 4  0
$ ./print_leap  # manual reading several hours later
sh: /usr/bin/ntpq: No such file or directory
1435727243.250130 114322849.876607481 0  0
$ ./print_leap 
sh: 1: /usr/bin/ntpq: not found
1435704263.521402 627240.363389922 1  0
[... skipping to the second before the leap second]
sh: 1: /usr/bin/ntpq: not found
1435708798.991150 631775.833122648 1  0
sh: 1: /usr/bin/ntpq: not found
1435708799.062267 631775.904240598 1  0
[... skipping to the leap second]
sh: 1: /usr/bin/ntpq: not found
1435708799.986215 631776.828187732 1  0
sh: 1: /usr/bin/ntpq: not found
1435708799.061678 631776.903650529 3  0
[... skipping to the second after the leap second]
sh: 1: /usr/bin/ntpq: not found
1435708799.987007 631777.828979335 3  0
sh: 1: /usr/bin/ntpq: not found
1435708800.061094 631777.903067236 4  0
[... skipping to the last programmatic reading]
sh: 1: /usr/bin/ntpq: not found
1435708921.380148 631899.222124765 4  0
$ ./print_leap  # manual reading several hours later
sh: 1: /usr/bin/ntpq: not found
1435727152.545742 650130.387735253 0  0
NTP公共池问题 did中的某些服务器。如果运气不好,当池中的所有上游服务器都无法宣布闰秒时,您将永远不会知道。因此,如果本地应用程序需要闰秒警告,则必须使用配置文件将闰秒通知本地NTP守护程序

故障/不一致 当按顺序查询当前时间和当前闰秒状态时,很明显这些值可能不一致,因为两个函数调用之间经过的时间不同

但是,观察到了无法用调用之间经过的时间来解释的其他不一致性。两台计算机(系统4和7)以gettimeofday返回的时间值143570800开始闰秒,然后在下次读取时切换回1435708799。 两台计算机,系统6和7,在闰秒后的第二秒启动,adjtimex值仍指示th