Postfix3.3.1
sane_time.c
[詳解]
1 /*++
2 /* NAME
3 /* sane_time 3
4 /* SUMMARY
5 /* time(2) with backward time jump protection.
6 /* SYNOPSIS
7 /* #include <sane_time.h>
8 /*
9 /* time_t sane_time(void)
10 /*
11 /* DESCRIPTION
12 /* This module provides time(2) like call for applications
13 /* which need monotonically increasing time function rather
14 /* than the real exact time. It eliminates the need for various
15 /* workarounds all over the application which would handle
16 /* potential problems if time suddenly jumps backward.
17 /* Instead we choose to deal with this problem inside this
18 /* module and let the application focus on its own tasks.
19 /*
20 /* sane_time() returns the current timestamp as obtained from
21 /* time(2) call, at least most of the time. In case this routine
22 /* detects that time has jumped backward, it keeps returning
23 /* whatever timestamp it returned before, until this timestamp
24 /* and the time(2) timestamp become synchronized again.
25 /* Additionally, the returned timestamp is slowly increased to
26 /* prevent the faked clock from freezing for too long.
27 /* SEE ALSO
28 /* time(2) get current time
29 /* DIAGNOSTICS
30 /* Warning message is logged if backward time jump is detected.
31 /* LICENSE
32 /* .ad
33 /* .fi
34 /* The Secure Mailer license must be distributed with this software.
35 /* AUTHOR(S)
36 /* Patrik Rak
37 /* Modra 6
38 /* 155 00, Prague, Czech Republic
39 /*--*/
40 
41 /* System library. */
42 
43 #include <sys_defs.h>
44 
45 /* Utility library. */
46 
47 #include <msg.h>
48 
49 /* Application-specific. */
50 
51 #include "sane_time.h"
52 
53 /*
54  * How many times shall we slow down the real clock when recovering from
55  * time jump.
56  */
57 #define SLEW_FACTOR 2
58 
59 /* sane_time - get current time, protected against time warping */
60 
61 time_t sane_time(void)
62 {
63  time_t now;
64  static time_t last_time, last_real;
65  long delta;
66  static int fraction;
67  static int warned;
68 
69  now = time((time_t *) 0);
70 
71  if ((delta = now - last_time) < 0 && last_time != 0) {
72  if ((delta = now - last_real) < 0) {
73  msg_warn("%sbackward time jump detected -- slewing clock",
74  warned++ ? "another " : "");
75  } else {
76  delta += fraction;
77  last_time += delta / SLEW_FACTOR;
78  fraction = delta % SLEW_FACTOR;
79  }
80  } else {
81  if (warned) {
82  warned = 0;
83  msg_warn("backward time jump recovered -- back to normality");
84  fraction = 0;
85  }
86  last_time = now;
87  }
88  last_real = now;
89 
90  return (last_time);
91 }
92 
93 #ifdef TEST
94 
95  /*
96  * Proof-of-concept test program. Repeatedly print current system time and
97  * time returned by sane_time(). Meanwhile, try stepping your system clock
98  * back and forth to see what happens.
99  */
100 
101 #include <stdlib.h>
102 #include <msg_vstream.h>
103 #include <iostuff.h> /* doze() */
104 
105 int main(int argc, char **argv)
106 {
107  int delay = 1000000;
108  time_t now;
109 
110  msg_vstream_init(argv[0], VSTREAM_ERR);
111 
112  if (argc == 2 && (delay = atol(argv[1]) * 1000) > 0)
113  /* void */ ;
114  else if (argc != 1)
115  msg_fatal("usage: %s [delay in ms (default 1 second)]", argv[0]);
116 
117  for (;;) {
118  now = time((time_t *) 0);
119  vstream_printf("real: %s", ctime(&now));
120  now = sane_time();
121  vstream_printf("fake: %s\n", ctime(&now));
123  doze(delay);
124  }
125 }
126 
127 #endif
time_t sane_time(void)
Definition: sane_time.c:61
#define VSTREAM_OUT
Definition: vstream.h:67
int main(int argc, char **argv)
Definition: anvil.c:1010
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
void msg_warn(const char *fmt,...)
Definition: msg.c:215
void doze(unsigned delay)
Definition: doze.c:44
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
#define SLEW_FACTOR
Definition: sane_time.c:57
void msg_vstream_init(const char *name, VSTREAM *vp)
Definition: msg_vstream.c:77
#define VSTREAM_ERR
Definition: vstream.h:68