/* * include/haproxy/ticks.h * Functions and macros for manipulation of expiration timers * * Copyright (C) 2000-2020 Willy Tarreau - w@1wt.eu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, version 2.1 * exclusively. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * Using a mix of milliseconds and timeval for internal timers is expensive and * overkill, because we don't need such a precision to compute timeouts. * So we're converting them to "ticks". * * A tick is a representation of a date relative to another one, and is * measured in milliseconds. The natural usage is to represent an absolute date * relative to the current date. Since it is not practical to update all values * each time the current date changes, instead we use the absolute date rounded * down to fit in a tick. We then have to compare a tick to the current date to * know whether it is in the future or in the past. If a tick is below the * current date, it is in the past. If it is above, it is in the future. The * values will wrap so we can't compare that easily, instead we check the sign * of the difference between a tick and the current date. * * Proceeding like this allows us to manipulate dates that are stored in * scalars with enough precision and range. For this reason, we store ticks in * 32-bit integers. This is enough to handle dates that are between 24.85 days * in the past and as much in the future. * * We must both support absolute dates (well in fact, dates relative to now+/- * 24 days), and intervals (for timeouts). Both types need an "eternity" magic * value. For optimal code generation, we'll use zero as the magic value * indicating that an expiration timer or a timeout is not set. We have to * check that we don't return this value when adding timeouts to . If a * computation returns 0, we must increase it to 1 (which will push the timeout * 1 ms further). For this reason, timeouts must not be added by hand but via * the dedicated tick_add() function. */ #ifndef _HAPROXY_TICKS_H #define _HAPROXY_TICKS_H #include #define TICK_ETERNITY 0 /* right now, ticks are milliseconds. Both negative ms and negative ticks * indicate eternity. */ #define MS_TO_TICKS(ms) (ms) #define TICKS_TO_MS(tk) (tk) /* currently updated and stored in time.c */ extern THREAD_LOCAL unsigned int now_ms; /* internal date in milliseconds (may wrap) */ extern volatile unsigned int global_now_ms; /* return 1 if tick is set, otherwise 0 */ static inline int tick_isset(int expire) { return expire != 0; } /* Add to , and return the resulting expiration date. * will not be checked for null values. */ static inline int tick_add(int now, int timeout) { now += timeout; if (unlikely(!now)) now++; /* unfortunate value */ return now; } /* add to if it is set, otherwise set it to eternity. * Return the resulting expiration date. */ static inline int tick_add_ifset(int now, int timeout) { if (!timeout) return TICK_ETERNITY; return tick_add(now, timeout); } /* return 1 if timer is before , none of which can be infinite. */ static inline int tick_is_lt(int t1, int t2) { return (t1 - t2) < 0; } /* return 1 if timer is before or equal to , none of which can be infinite. */ static inline int tick_is_le(int t1, int t2) { return (t1 - t2) <= 0; } /* return 1 if timer is expired at date , otherwise zero */ static inline int tick_is_expired(int timer, int now) { if (unlikely(!tick_isset(timer))) return 0; if (unlikely((timer - now) <= 0)) return 1; return 0; } /* return the first one of the two timers, both of which may be infinite */ static inline int tick_first(int t1, int t2) { if (!tick_isset(t1)) return t2; if (!tick_isset(t2)) return t1; if ((t1 - t2) <= 0) return t1; else return t2; } /* return the first one of the two timers, where only the first one may be infinite */ static inline int tick_first_2nz(int t1, int t2) { if (!tick_isset(t1)) return t2; if ((t1 - t2) <= 0) return t1; else return t2; } /* return the number of ticks remaining from to , or zero if expired */ static inline int tick_remain(int now, int exp) { if (tick_is_expired(exp, now)) return 0; return exp - now; } #endif /* _HAPROXY_TICKS_H */ /* * Local variables: * c-indent-level: 8 * c-basic-offset: 8 * End: */