1 /*
2  * include/haproxy/ticks.h
3  * Functions and macros for manipulation of expiration timers
4  *
5  * Copyright (C) 2000-2020 Willy Tarreau - w@1wt.eu
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation, version 2.1
10  * exclusively.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 /*
23  * Using a mix of milliseconds and timeval for internal timers is expensive and
24  * overkill, because we don't need such a precision to compute timeouts.
25  * So we're converting them to "ticks".
26  *
27  * A tick is a representation of a date relative to another one, and is
28  * measured in milliseconds. The natural usage is to represent an absolute date
29  * relative to the current date. Since it is not practical to update all values
30  * each time the current date changes, instead we use the absolute date rounded
31  * down to fit in a tick. We then have to compare a tick to the current date to
32  * know whether it is in the future or in the past. If a tick is below the
33  * current date, it is in the past. If it is above, it is in the future. The
34  * values will wrap so we can't compare that easily, instead we check the sign
35  * of the difference between a tick and the current date.
36  *
37  * Proceeding like this allows us to manipulate dates that are stored in
38  * scalars with enough precision and range. For this reason, we store ticks in
39  * 32-bit integers. This is enough to handle dates that are between 24.85 days
40  * in the past and as much in the future.
41  *
42  * We must both support absolute dates (well in fact, dates relative to now+/-
43  * 24 days), and intervals (for timeouts). Both types need an "eternity" magic
44  * value. For optimal code generation, we'll use zero as the magic value
45  * indicating that an expiration timer or a timeout is not set. We have to
46  * check that we don't return this value when adding timeouts to <now>. If a
47  * computation returns 0, we must increase it to 1 (which will push the timeout
48  * 1 ms further). For this reason, timeouts must not be added by hand but via
49  * the dedicated tick_add() function.
50  */
51 
52 #ifndef _HAPROXY_TICKS_H
53 #define _HAPROXY_TICKS_H
54 
55 #include <haproxy/api.h>
56 
57 #define TICK_ETERNITY   0
58 
59 /* right now, ticks are milliseconds. Both negative ms and negative ticks
60  * indicate eternity.
61  */
62 #define MS_TO_TICKS(ms) (ms)
63 #define TICKS_TO_MS(tk) (tk)
64 
65 /* return 1 if tick is set, otherwise 0 */
tick_isset(int expire)66 static inline int tick_isset(int expire)
67 {
68 	return expire != 0;
69 }
70 
71 /* Add <timeout> to <now>, and return the resulting expiration date.
72  * <timeout> will not be checked for null values.
73  */
tick_add(int now,int timeout)74 static inline int tick_add(int now, int timeout)
75 {
76 	now += timeout;
77 	if (unlikely(!now))
78 		now++;    /* unfortunate value */
79 	return now;
80 }
81 
82 /* add <timeout> to <now> if it is set, otherwise set it to eternity.
83  * Return the resulting expiration date.
84  */
tick_add_ifset(int now,int timeout)85 static inline int tick_add_ifset(int now, int timeout)
86 {
87 	if (!timeout)
88 		return TICK_ETERNITY;
89 	return tick_add(now, timeout);
90 }
91 
92 /* return 1 if timer <t1> is before <t2>, none of which can be infinite. */
tick_is_lt(int t1,int t2)93 static inline int tick_is_lt(int t1, int t2)
94 {
95 	return (t1 - t2) < 0;
96 }
97 
98 /* return 1 if timer <t1> is before or equal to <t2>, none of which can be infinite. */
tick_is_le(int t1,int t2)99 static inline int tick_is_le(int t1, int t2)
100 {
101 	return (t1 - t2) <= 0;
102 }
103 
104 /* return 1 if timer <timer> is expired at date <now>, otherwise zero */
tick_is_expired(int timer,int now)105 static inline int tick_is_expired(int timer, int now)
106 {
107 	if (unlikely(!tick_isset(timer)))
108 		return 0;
109 	if (unlikely((timer - now) <= 0))
110 		return 1;
111 	return 0;
112 }
113 
114 /* return the first one of the two timers, both of which may be infinite */
tick_first(int t1,int t2)115 static inline int tick_first(int t1, int t2)
116 {
117 	if (!tick_isset(t1))
118 		return t2;
119 	if (!tick_isset(t2))
120 		return t1;
121 	if ((t1 - t2) <= 0)
122 		return t1;
123 	else
124 		return t2;
125 }
126 
127 /* return the first one of the two timers, where only the first one may be infinite */
tick_first_2nz(int t1,int t2)128 static inline int tick_first_2nz(int t1, int t2)
129 {
130 	if (!tick_isset(t1))
131 		return t2;
132 	if ((t1 - t2) <= 0)
133 		return t1;
134 	else
135 		return t2;
136 }
137 
138 /* return the number of ticks remaining from <now> to <exp>, or zero if expired */
tick_remain(int now,int exp)139 static inline int tick_remain(int now, int exp)
140 {
141 	if (tick_is_expired(exp, now))
142 		return 0;
143 	return exp - now;
144 }
145 
146 #endif /* _HAPROXY_TICKS_H */
147 
148 /*
149  * Local variables:
150  *  c-indent-level: 8
151  *  c-basic-offset: 8
152  * End:
153  */
154