acpid: update to 2.0.28
[feed/packages.git] / net / haproxy / patches / 0008-MINOR-tools-add-a-portable-timegm-alternative.patch
1 From 3e21b8d25ad148ef4e6544f28a8b2305f9484a7b Mon Sep 17 00:00:00 2001
2 From: Willy Tarreau <w@1wt.eu>
3 Date: Wed, 19 Jul 2017 19:05:29 +0200
4 Subject: [PATCH 08/18] MINOR: tools: add a portable timegm() alternative
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 timegm() is not provided everywhere and the documentation on how to
10 replace it is bogus as it proposes an inefficient and non-thread safe
11 alternative.
12
13 Here we reimplement everything needed to compute the number of seconds
14 since Epoch based on the broken down fields in struct tm. It is only
15 guaranteed to return correct values for correct inputs. It was successfully
16 tested with all possible 32-bit values of time_t converted to struct tm
17 using gmtime() and back to time_t using the legacy timegm() and this
18 function, and both functions always produced the same result.
19
20 Thanks to BenoƮt Garnier for an instructive discussion and detailed
21 explanations of the various time functions, leading to this solution.
22 (cherry picked from commit cb1949b8b30b8db7e05546da2939eff2b5973321)
23
24 Signed-off-by: Willy Tarreau <w@1wt.eu>
25 ---
26 include/common/standard.h | 21 ++++++++++++++++++
27 src/standard.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++
28 2 files changed, 75 insertions(+)
29
30 diff --git a/include/common/standard.h b/include/common/standard.h
31 index 87f90a65..c19c368b 100644
32 --- a/include/common/standard.h
33 +++ b/include/common/standard.h
34 @@ -624,6 +624,27 @@ static inline void get_gmtime(const time_t now, struct tm *tm)
35 gmtime_r(&now, tm);
36 }
37
38 +/* Counts a number of elapsed days since 01/01/0000 based solely on elapsed
39 + * years and assuming the regular rule for leap years applies. It's fake but
40 + * serves as a temporary origin. It's worth remembering that it's the first
41 + * year of each period that is leap and not the last one, so for instance year
42 + * 1 sees 366 days since year 0 was leap. For this reason we have to apply
43 + * modular arithmetics which is why we offset the year by 399 before
44 + * subtracting the excess at the end. No overflow here before ~11.7 million
45 + * years.
46 + */
47 +static inline unsigned int days_since_zero(unsigned int y)
48 +{
49 + return y * 365 + (y + 399) / 4 - (y + 399) / 100 + (y + 399) / 400
50 + - 399 / 4 + 399 / 100;
51 +}
52 +
53 +/* Returns the number of seconds since 01/01/1970 0:0:0 GMT for GMT date <tm>.
54 + * It is meant as a portable replacement for timegm() for use with valid inputs.
55 + * Returns undefined results for invalid dates (eg: months out of range 0..11).
56 + */
57 +extern time_t my_timegm(const struct tm *tm);
58 +
59 /* This function parses a time value optionally followed by a unit suffix among
60 * "d", "h", "m", "s", "ms" or "us". It converts the value into the unit
61 * expected by the caller. The computation does its best to avoid overflows.
62 diff --git a/src/standard.c b/src/standard.c
63 index 8df1da6c..e1d414f3 100644
64 --- a/src/standard.c
65 +++ b/src/standard.c
66 @@ -2841,6 +2841,60 @@ char *localdate2str_log(char *dst, time_t t, struct tm *tm, size_t size)
67 return dst;
68 }
69
70 +/* Returns the number of seconds since 01/01/1970 0:0:0 GMT for GMT date <tm>.
71 + * It is meant as a portable replacement for timegm() for use with valid inputs.
72 + * Returns undefined results for invalid dates (eg: months out of range 0..11).
73 + */
74 +time_t my_timegm(const struct tm *tm)
75 +{
76 + /* Each month has 28, 29, 30 or 31 days, or 28+N. The date in the year
77 + * is thus (current month - 1)*28 + cumulated_N[month] to count the
78 + * sum of the extra N days for elapsed months. The sum of all these N
79 + * days doesn't exceed 30 for a complete year (366-12*28) so it fits
80 + * in a 5-bit word. This means that with 60 bits we can represent a
81 + * matrix of all these values at once, which is fast and efficient to
82 + * access. The extra February day for leap years is not counted here.
83 + *
84 + * Jan : none = 0 (0)
85 + * Feb : Jan = 3 (3)
86 + * Mar : Jan..Feb = 3 (3 + 0)
87 + * Apr : Jan..Mar = 6 (3 + 0 + 3)
88 + * May : Jan..Apr = 8 (3 + 0 + 3 + 2)
89 + * Jun : Jan..May = 11 (3 + 0 + 3 + 2 + 3)
90 + * Jul : Jan..Jun = 13 (3 + 0 + 3 + 2 + 3 + 2)
91 + * Aug : Jan..Jul = 16 (3 + 0 + 3 + 2 + 3 + 2 + 3)
92 + * Sep : Jan..Aug = 19 (3 + 0 + 3 + 2 + 3 + 2 + 3 + 3)
93 + * Oct : Jan..Sep = 21 (3 + 0 + 3 + 2 + 3 + 2 + 3 + 3 + 2)
94 + * Nov : Jan..Oct = 24 (3 + 0 + 3 + 2 + 3 + 2 + 3 + 3 + 2 + 3)
95 + * Dec : Jan..Nov = 26 (3 + 0 + 3 + 2 + 3 + 2 + 3 + 3 + 2 + 3 + 2)
96 + */
97 + uint64_t extra =
98 + ( 0ULL << 0*5) + ( 3ULL << 1*5) + ( 3ULL << 2*5) + /* Jan, Feb, Mar, */
99 + ( 6ULL << 3*5) + ( 8ULL << 4*5) + (11ULL << 5*5) + /* Apr, May, Jun, */
100 + (13ULL << 6*5) + (16ULL << 7*5) + (19ULL << 8*5) + /* Jul, Aug, Sep, */
101 + (21ULL << 9*5) + (24ULL << 10*5) + (26ULL << 11*5); /* Oct, Nov, Dec, */
102 +
103 + unsigned int y = tm->tm_year + 1900;
104 + unsigned int m = tm->tm_mon;
105 + unsigned long days = 0;
106 +
107 + /* days since 1/1/1970 for full years */
108 + days += days_since_zero(y) - days_since_zero(1970);
109 +
110 + /* days for full months in the current year */
111 + days += 28 * m + ((extra >> (m * 5)) & 0x1f);
112 +
113 + /* count + 1 after March for leap years. A leap year is a year multiple
114 + * of 4, unless it's multiple of 100 without being multiple of 400. 2000
115 + * is leap, 1900 isn't, 1904 is.
116 + */
117 + if ((m > 1) && !(y & 3) && ((y % 100) || !(y % 400)))
118 + days++;
119 +
120 + days += tm->tm_mday - 1;
121 + return days * 86400ULL + tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
122 +}
123 +
124 /* This function check a char. It returns true and updates
125 * <date> and <len> pointer to the new position if the
126 * character is found.
127 --
128 2.13.0
129