Read the system boot time from /proc instead of computing

Read the time of system boot from /proc/stat (entry: btime) instead
of computing it as the difference between the current time and the
uptime. This is the only way to get a consistent result which won't
possibly change from one run to the next.

The problems with the original code were:
* Both the current time and the uptime are rounded down to the second,
  but the system doesn't boot on an integer second value so they do not
  tick at the same moment. Thus, the rounding errors can cause a one
  second difference from one run to the next.
* We can't read the uptime and the current time at the exact same moment
  anyway, so the time difference we compute is bound to be inaccurate.
Bug-Redhat: https://bugzilla.redhat.com/show_bug.cgi?id=222251
Author: Jean Delvare <jdelvare@suse.de>
Reviewed-by: Craig Small <csmall@debian.org>
This commit is contained in:
Jan Görig
2010-12-16 10:30:39 +01:00
parent 9e6370a886
commit 4d3c19af52
4 changed files with 35 additions and 7 deletions

View File

@ -10,7 +10,7 @@ global:
openproc; closeproc;
tty_to_dev; dev_to_tty; open_psdb_message; open_psdb; lookup_wchan;
display_version; procps_version; linux_version_code;
Hertz; smp_num_cpus; have_privs;
Hertz; smp_num_cpus; have_privs; getbtime;
sprint_uptime; uptime; user_from_uid; print_uptime; loadavg;
pretty_print_signals; print_given_signals; unix_print_signals; signal_name_to_number; signal_number_to_name;
meminfo; vminfo; getstat; getdiskstat; getpartitions_num; getslabinfo; get_pid_digits;

View File

@ -90,6 +90,35 @@ int uptime(double *restrict uptime_secs, double *restrict idle_secs) {
return up; /* assume never be zero seconds in practice */
}
unsigned long getbtime(void) {
static unsigned long btime = 0;
FILE *f;
if (btime)
return btime;
/* /proc/stat can get very large on multi-CPU systems so we
can't use FILE_TO_BUF */
if (!(f = fopen(STAT_FILE, "r"))) {
fputs(BAD_OPEN_MESSAGE, stderr);
fflush(NULL);
_exit(102);
}
while ((fgets(buf, sizeof buf, f))) {
if (sscanf(buf, "btime %lu", &btime) == 1)
break;
}
fclose(f);
if (!btime) {
fputs("missing btime in " STAT_FILE "\n", stderr);
exit(1);
}
return btime;
}
/***********************************************************************
* Some values in /proc are expressed in units of 1/HZ seconds, where HZ
* is the kernel clock tick rate. One of these units is called a jiffy.

View File

@ -17,6 +17,7 @@ extern void eight_cpu_numbers(JT *uret, JT *nret, JT *sret, JT *iret, JT *wret,
#endif
extern int uptime (double *uptime_secs, double *idle_secs);
extern unsigned long getbtime(void);
extern void loadavg(double *av1, double *av5, double *av15);