/src/haproxy/include/haproxy/ticks.h
Line | Count | Source |
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 | | /* currently updated and stored in time.c */ |
66 | | extern THREAD_LOCAL unsigned int now_ms; /* internal date in milliseconds (may wrap) */ |
67 | | extern volatile unsigned int *global_now_ms; |
68 | | |
69 | | /* return 1 if tick is set, otherwise 0 */ |
70 | | static inline int tick_isset(int expire) |
71 | 0 | { |
72 | 0 | return expire != 0; |
73 | 0 | } |
74 | | |
75 | | /* Add <timeout> to <now>, and return the resulting expiration date. |
76 | | * <timeout> will not be checked for null values. |
77 | | */ |
78 | | static inline int tick_add(int now, int timeout) |
79 | 0 | { |
80 | 0 | now += timeout; |
81 | 0 | if (unlikely(!now)) |
82 | 0 | now++; /* unfortunate value */ |
83 | 0 | return now; |
84 | 0 | } |
85 | | |
86 | | /* add <timeout> to <now> if it is set, otherwise set it to eternity. |
87 | | * Return the resulting expiration date. |
88 | | */ |
89 | | static inline int tick_add_ifset(int now, int timeout) |
90 | 0 | { |
91 | 0 | if (!timeout) |
92 | 0 | return TICK_ETERNITY; |
93 | 0 | return tick_add(now, timeout); |
94 | 0 | } |
95 | | |
96 | | /* return 1 if timer <t1> is before <t2>, none of which can be infinite. */ |
97 | | static inline int tick_is_lt(int t1, int t2) |
98 | 0 | { |
99 | 0 | return (t1 - t2) < 0; |
100 | 0 | } |
101 | | |
102 | | /* return 1 if timer <t1> is before or equal to <t2>, none of which can be infinite. */ |
103 | | static inline int tick_is_le(int t1, int t2) |
104 | 0 | { |
105 | 0 | return (t1 - t2) <= 0; |
106 | 0 | } |
107 | | |
108 | | /* return 1 if timer <timer> is expired at date <now>, otherwise zero */ |
109 | | static inline int tick_is_expired(int timer, int now) |
110 | 0 | { |
111 | 0 | if (unlikely(!tick_isset(timer))) |
112 | 0 | return 0; |
113 | 0 | if (unlikely((timer - now) <= 0)) |
114 | 0 | return 1; |
115 | 0 | return 0; |
116 | 0 | } |
117 | | |
118 | | /* return the first one of the two timers, both of which may be infinite */ |
119 | | static inline int tick_first(int t1, int t2) |
120 | 0 | { |
121 | 0 | if (!tick_isset(t1)) |
122 | 0 | return t2; |
123 | 0 | if (!tick_isset(t2)) |
124 | 0 | return t1; |
125 | 0 | if ((t1 - t2) <= 0) |
126 | 0 | return t1; |
127 | 0 | else |
128 | 0 | return t2; |
129 | 0 | } |
130 | | |
131 | | /* return the first one of the two timers, where only the first one may be infinite */ |
132 | | static inline int tick_first_2nz(int t1, int t2) |
133 | 0 | { |
134 | 0 | if (!tick_isset(t1)) |
135 | 0 | return t2; |
136 | 0 | if ((t1 - t2) <= 0) |
137 | 0 | return t1; |
138 | 0 | else |
139 | 0 | return t2; |
140 | 0 | } |
141 | | |
142 | | /* return the number of ticks remaining from <now> to <exp>, or zero if expired */ |
143 | | static inline int tick_remain(int now, int exp) |
144 | 0 | { |
145 | 0 | if (tick_is_expired(exp, now)) |
146 | 0 | return 0; |
147 | 0 | return exp - now; |
148 | 0 | } |
149 | | |
150 | | #endif /* _HAPROXY_TICKS_H */ |
151 | | |
152 | | /* |
153 | | * Local variables: |
154 | | * c-indent-level: 8 |
155 | | * c-basic-offset: 8 |
156 | | * End: |
157 | | */ |