include/common/time.h
Time calculation functions and macros.
- Copyright (C) 2000-2006 Willy Tarreau - w@1wt.eu
+ Copyright (C) 2000-2007 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
#include <stdlib.h>
#include <sys/time.h>
#include <common/config.h>
+#include <common/standard.h>
/* eternity when exprimed in timeval */
#ifndef TV_ETERNITY
extern struct timeval start_date; /* the process's start date */
+/**** exported functions *************************************************/
+
+
/*
* adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
*/
-REGPRM3 struct timeval *tv_delayfrom(struct timeval *tv, const struct timeval *from, int ms);
+REGPRM3 struct timeval *tv_ms_add(struct timeval *tv, const struct timeval *from, int ms);
/*
* compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
- * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
+ * Must not be used when either argument is eternity. Use tv_ms_cmp2() for that.
*/
-REGPRM2 int tv_cmp_ms(const struct timeval *tv1, const struct timeval *tv2);
+REGPRM2 int tv_ms_cmp(const struct timeval *tv1, const struct timeval *tv2);
/*
* compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
* assuming that TV_ETERNITY is greater than everything.
*/
-REGPRM2 int tv_cmp2_ms(const struct timeval *tv1, const struct timeval *tv2);
+REGPRM2 int tv_ms_cmp2(const struct timeval *tv1, const struct timeval *tv2);
+
+/**** general purpose functions and macros *******************************/
-/*
- * compares <tv1> and <tv2> modulo 1 ms: returns 1 if tv1 <= tv2, 0 if tv1 > tv2,
- * assuming that TV_ETERNITY is greater than everything. Returns 0 if tv1 is
- * TV_ETERNITY, and always assumes that tv2 != TV_ETERNITY. Designed to replace
- * occurrences of (tv_cmp2_ms(tv,now) <= 0).
- */
-REGPRM2 int tv_cmp2_le(const struct timeval *tv1, const struct timeval *tv2);
+
+/* tv_now: sets <tv> to the current time */
+REGPRM1 static inline struct timeval *tv_now(struct timeval *tv)
+{
+ gettimeofday(tv, NULL);
+ return tv;
+}
/*
- * returns the remaining time between tv1=now and event=tv2
- * if tv2 is passed, 0 is returned.
- * Returns TIME_ETERNITY if tv2 is eternity.
+ * sets a struct timeval to its highest value so that it can never happen
+ * note that only tv_usec is necessary to detect it since a tv_usec > 999999
+ * is normally not possible.
+ *
*/
-REGPRM2 unsigned long tv_remain2(const struct timeval *tv1, const struct timeval *tv2);
-/* sets <tv> to the current time */
-REGPRM1 static inline struct timeval *tv_now(struct timeval *tv)
+REGPRM1 static inline struct timeval *tv_eternity(struct timeval *tv)
{
- if (tv)
- gettimeofday(tv, NULL);
+ tv->tv_sec = tv->tv_usec = TV_ETERNITY;
return tv;
}
/*
- * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
+ * sets a struct timeval to 0
+ *
*/
-REGPRM2 static inline int tv_cmp(const struct timeval *tv1, const struct timeval *tv2)
+REGPRM1 static inline struct timeval *tv_zero(struct timeval *tv) {
+ tv->tv_sec = tv->tv_usec = 0;
+ return tv;
+}
+
+/*
+ * returns non null if tv is [eternity], otherwise 0.
+ */
+#define tv_iseternity(tv) ((tv)->tv_usec == TV_ETERNITY)
+
+/*
+ * returns non null if tv is [0], otherwise 0.
+ */
+#define tv_iszero(tv) (((tv)->tv_sec | (tv)->tv_usec) == 0)
+
+
+/**** comparision functions and macros ***********************************/
+
+
+/* tv_cmp: compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2. */
+REGPRM2 static inline int __tv_cmp(const struct timeval *tv1, const struct timeval *tv2)
{
if ((unsigned)tv1->tv_sec < (unsigned)tv2->tv_sec)
return -1;
return 0;
}
+/* tv_iseq: compares <tv1> and <tv2> : returns 1 if tv1 == tv2, otherwise 0 */
+REGPRM2 static inline int __tv_iseq(const struct timeval *tv1, const struct timeval *tv2)
+{
+ return ((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec) &&
+ ((unsigned)tv1->tv_usec == (unsigned)tv2->tv_usec);
+}
+
+/* tv_isgt: compares <tv1> and <tv2> : returns 1 if tv1 > tv2, otherwise 0 */
+REGPRM2 static inline int __tv_isgt(const struct timeval *tv1, const struct timeval *tv2)
+{
+ return
+ ((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec) ?
+ ((unsigned)tv1->tv_usec > (unsigned)tv2->tv_usec) :
+ ((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec);
+}
+
+/* tv_isge: compares <tv1> and <tv2> : returns 1 if tv1 >= tv2, otherwise 0 */
+REGPRM2 static inline int __tv_isge(const struct timeval *tv1, const struct timeval *tv2)
+{
+ return
+ ((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec) ?
+ ((unsigned)tv1->tv_usec >= (unsigned)tv2->tv_usec) :
+ ((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec);
+}
+
+/* tv_islt: compares <tv1> and <tv2> : returns 1 if tv1 < tv2, otherwise 0 */
+REGPRM2 static inline int __tv_islt(const struct timeval *tv1, const struct timeval *tv2)
+{
+ return
+ ((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec) ?
+ ((unsigned)tv1->tv_usec < (unsigned)tv2->tv_usec) :
+ ((unsigned)tv1->tv_sec < (unsigned)tv2->tv_sec);
+}
+
+/* tv_isle: compares <tv1> and <tv2> : returns 1 if tv1 <= tv2, otherwise 0 */
+REGPRM2 static inline int __tv_isle(const struct timeval *tv1, const struct timeval *tv2)
+{
+ return
+ ((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec) ?
+ ((unsigned)tv1->tv_usec <= (unsigned)tv2->tv_usec) :
+ ((unsigned)tv1->tv_sec < (unsigned)tv2->tv_sec);
+}
+
/*
- * compares <tv1> and <tv2> : returns 0 if tv1 < tv2, 1 if tv1 >= tv2
+ * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
+ * Must not be used when either argument is eternity. Use tv_ms_cmp2() for that.
*/
-REGPRM2 static inline int tv_cmp_ge(const struct timeval *tv1, const struct timeval *tv2)
+#define tv_ms_cmp _tv_ms_cmp
+REGPRM2 int _tv_ms_cmp(const struct timeval *tv1, const struct timeval *tv2);
+REGPRM2 static inline int __tv_ms_cmp(const struct timeval *tv1, const struct timeval *tv2)
{
- if ((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec)
+ if ((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec) {
+ if ((unsigned)tv2->tv_usec >= (unsigned)tv1->tv_usec + 1000)
+ return -1;
+ else if ((unsigned)tv1->tv_usec >= (unsigned)tv2->tv_usec + 1000)
+ return 1;
+ else
+ return 0;
+ }
+ else if (((unsigned)tv2->tv_sec > (unsigned)tv1->tv_sec + 1) ||
+ (((unsigned)tv2->tv_sec == (unsigned)tv1->tv_sec + 1) &&
+ ((unsigned)tv2->tv_usec + 1000000 >= (unsigned)tv1->tv_usec + 1000)))
+ return -1;
+ else if (((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec + 1) ||
+ (((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec + 1) &&
+ ((unsigned)tv1->tv_usec + 1000000 >= (unsigned)tv2->tv_usec + 1000)))
return 1;
- if ((unsigned)tv1->tv_sec < (unsigned)tv2->tv_sec)
+ else
return 0;
- if ((unsigned)tv1->tv_usec >= (unsigned)tv2->tv_usec)
+}
+
+/*
+ * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
+ * assuming that TV_ETERNITY is greater than everything.
+ */
+#define tv_ms_cmp2 _tv_ms_cmp2
+REGPRM2 int _tv_ms_cmp2(const struct timeval *tv1, const struct timeval *tv2);
+REGPRM2 static inline int __tv_ms_cmp2(const struct timeval *tv1, const struct timeval *tv2)
+{
+ if (tv_iseternity(tv1))
+ if (tv_iseternity(tv2))
+ return 0; /* same */
+ else
+ return 1; /* tv1 later than tv2 */
+ else if (tv_iseternity(tv2))
+ return -1; /* tv2 later than tv1 */
+ return tv_ms_cmp(tv1, tv2);
+}
+
+/*
+ * compares <tv1> and <tv2> modulo 1 ms: returns 1 if tv1 <= tv2, 0 if tv1 > tv2,
+ * assuming that TV_ETERNITY is greater than everything. Returns 0 if tv1 is
+ * TV_ETERNITY, and always assumes that tv2 != TV_ETERNITY. Designed to replace
+ * occurrences of (tv_ms_cmp2(tv,now) <= 0).
+ */
+#define tv_ms_le2 _tv_ms_le2
+REGPRM2 int _tv_ms_le2(const struct timeval *tv1, const struct timeval *tv2);
+REGPRM2 static inline int __tv_ms_le2(const struct timeval *tv1, const struct timeval *tv2)
+{
+ if (likely((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec + 1))
+ return 0;
+
+ if (likely((unsigned)tv1->tv_sec < (unsigned)tv2->tv_sec))
+ return 1;
+
+ if (likely((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec)) {
+ if ((unsigned)tv2->tv_usec >= (unsigned)tv1->tv_usec + 1000)
+ return 1;
+ else
+ return 0;
+ }
+
+ if (unlikely(((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec + 1) &&
+ ((unsigned)tv1->tv_usec + 1000000 >= (unsigned)tv2->tv_usec + 1000)))
+ return 0;
+ else
return 1;
- return 0;
}
+
+/**** operators **********************************************************/
+
+
/*
- * returns the difference, in ms, between tv1 and tv2
+ * Returns the time in ms elapsed between tv1 and tv2, assuming that tv1<=tv2.
* Must not be used when either argument is eternity.
*/
-REGPRM2 static inline unsigned long tv_diff(const struct timeval *tv1, const struct timeval *tv2)
+#define tv_ms_elapsed __tv_ms_elapsed
+REGPRM2 unsigned long _tv_ms_elapsed(const struct timeval *tv1, const struct timeval *tv2);
+REGPRM2 static inline unsigned long __tv_ms_elapsed(const struct timeval *tv1, const struct timeval *tv2)
{
unsigned long ret;
-
- ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
- if ((unsigned)tv2->tv_usec > (unsigned)tv1->tv_usec)
- ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
- else
- ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
- return (unsigned long) ret;
+
+ ret = ((signed long)(tv2->tv_sec - tv1->tv_sec)) * 1000;
+ ret += ((signed long)(tv2->tv_usec - tv1->tv_usec)) / 1000;
+ return ret;
}
/*
* if tv2 is passed, 0 is returned.
* Must not be used when either argument is eternity.
*/
-REGPRM2 static inline unsigned long tv_remain(const struct timeval *tv1, const struct timeval *tv2)
+
+#define tv_ms_remain __tv_ms_remain
+REGPRM2 unsigned long _tv_ms_remain(const struct timeval *tv1, const struct timeval *tv2);
+REGPRM2 static inline unsigned long __tv_ms_remain(const struct timeval *tv1, const struct timeval *tv2)
{
- unsigned long ret;
-
- if (tv_cmp_ms(tv1, tv2) >= 0)
+ if (tv_ms_cmp(tv1, tv2) >= 0)
return 0; /* event elapsed */
- ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
- if ((unsigned)tv2->tv_usec > (unsigned)tv1->tv_usec)
- ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
- else
- ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
- return (unsigned long) ret;
+ return __tv_ms_elapsed(tv1, tv2);
}
-
/*
- * sets a struct timeval to its highest value so that it can never happen
- * note that only tv_usec is necessary to detect it since a tv_usec > 999999
- * is normally not possible.
- *
+ * returns the remaining time between tv1=now and event=tv2
+ * if tv2 is passed, 0 is returned.
+ * Returns TIME_ETERNITY if tv2 is eternity.
*/
-
-REGPRM1 static inline struct timeval *tv_eternity(struct timeval *tv)
+#define tv_ms_remain2 _tv_ms_remain2
+REGPRM2 unsigned long _tv_ms_remain2(const struct timeval *tv1, const struct timeval *tv2);
+REGPRM2 static inline unsigned long __tv_ms_remain2(const struct timeval *tv1, const struct timeval *tv2)
{
- tv->tv_sec = tv->tv_usec = TV_ETERNITY;
- return tv;
+ if (tv_iseternity(tv2))
+ return TIME_ETERNITY;
+
+ return tv_ms_remain(tv1, tv2);
}
/*
- * sets a struct timeval to 0
- *
+ * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
*/
-REGPRM1 static inline struct timeval *tv_zero(struct timeval *tv) {
- tv->tv_sec = tv->tv_usec = 0;
+#define tv_ms_add _tv_ms_add
+REGPRM3 struct timeval *_tv_ms_add(struct timeval *tv, const struct timeval *from, int ms);
+REGPRM3 static inline struct timeval *__tv_ms_add(struct timeval *tv, const struct timeval *from, int ms)
+{
+ tv->tv_usec = from->tv_usec + (ms % 1000) * 1000;
+ tv->tv_sec = from->tv_sec + (ms / 1000);
+ while (tv->tv_usec >= 1000000) {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec++;
+ }
return tv;
}
-/*
- * returns non null if tv is [eternity], otherwise 0.
- */
-#define tv_iseternity(tv) ((tv)->tv_usec == TV_ETERNITY)
-
-/*
- * returns non null if tv is [0], otherwise 0.
- */
-#define tv_iszero(tv) (((tv)->tv_sec | (tv)->tv_usec) == 0)
/*
* compares <tv1> and <tv2> : returns 1 if <tv1> is before <tv2>, otherwise 0.
t->qlist.p = NULL;
t->state = TASK_IDLE;
t->context = NULL;
- tv_delayfrom(&t->expire, &now, TBLCHKINT);
+ tv_ms_add(&t->expire, &now, TBLCHKINT);
task_queue(t);
t->process = appsession_refresh;
initialized ++;
for (element = list_head(&htbl->table[i]);
element != NULL; element = list_next(element)) {
asession = (appsess *)list_data(element);
- if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
+ if (tv_ms_le2(&asession->expire, &now)) {
if ((global.mode & MODE_DEBUG) &&
(!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
int len;
}
else
element = last;
- }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
+ }/* end if (tv_ms_le2(&asession->expire, &now)) */
else
last = element;
}/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
}
p = p->next;
}
- tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
+ tv_ms_add(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
return TBLCHKINT;
} /* end appsession_refresh */
}
if (s->be->contimeout)
- tv_delayfrom(&s->req->cex, &now, s->be->contimeout);
+ tv_ms_add(&s->req->cex, &now, s->be->contimeout);
else
tv_eternity(&s->req->cex);
return SN_ERR_NONE; /* connection is OK */
case SRV_STATUS_QUEUED:
/* FIXME-20060503 : we should use the queue timeout instead */
if (t->be->contimeout)
- tv_delayfrom(&t->req->cex, &now, t->be->contimeout);
+ tv_ms_add(&t->req->cex, &now, t->be->contimeout);
else
tv_eternity(&t->req->cex);
t->srv_state = SV_STIDLE;
t->context = newsrv;
/* check this every ms */
- tv_delayfrom(&t->expire, &now,
- newsrv->inter + mininter * srvpos / nbchk);
+ tv_ms_add(&t->expire, &now,
+ newsrv->inter + mininter * srvpos / nbchk);
task_queue(t);
//task_wakeup(&rq, t);
srvpos++;
fd = s->curfd;
if (fd < 0) { /* no check currently running */
//fprintf(stderr, "process_chk: 2\n");
- if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
+ if (!tv_ms_le2(&t->expire, &now)) { /* not good time yet */
task_queue(t); /* restore t to its place in the task list */
- return tv_remain2(&now, &t->expire);
+ return tv_ms_remain2(&now, &t->expire);
}
/* we don't send any health-checks when the proxy is stopped or when
* the server should not be checked.
*/
if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
- while (tv_cmp2_ms(&t->expire, &now) <= 0)
- tv_delayfrom(&t->expire, &t->expire, s->inter);
+ while (tv_ms_le2(&t->expire, &now))
+ tv_ms_add(&t->expire, &t->expire, s->inter);
task_queue(t); /* restore t to its place in the task list */
- return tv_remain2(&now, &t->expire);
+ return tv_ms_remain2(&now, &t->expire);
}
/* we'll initiate a new check */
assert (!EV_FD_ISSET(fd, DIR_RD));
#endif
/* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
- tv_delayfrom(&t->expire, &now, s->inter);
+ tv_ms_add(&t->expire, &now, s->inter);
task_queue(t); /* restore t to its place in the task list */
- return tv_remain(&now, &t->expire);
+ return tv_ms_remain(&now, &t->expire);
}
else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
s->result = -1; /* a real error */
if (!s->result) { /* nothing done */
//fprintf(stderr, "process_chk: 6\n");
- while (tv_cmp2_ms(&t->expire, &now) <= 0)
- tv_delayfrom(&t->expire, &t->expire, s->inter);
+ while (tv_ms_le2(&t->expire, &now))
+ tv_ms_add(&t->expire, &t->expire, s->inter);
goto new_chk; /* may be we should initialize a new check */
}
//fprintf(stderr, "process_chk: 7\n");
/* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
- while (tv_cmp2_ms(&t->expire, &now) <= 0)
- tv_delayfrom(&t->expire, &t->expire, s->inter);
+ while (tv_ms_le2(&t->expire, &now))
+ tv_ms_add(&t->expire, &t->expire, s->inter);
goto new_chk;
}
else {
}
s->curfd = -1; /* no check running anymore */
fd_delete(fd);
- while (tv_cmp2_ms(&t->expire, &now) <= 0)
- tv_delayfrom(&t->expire, &t->expire, s->inter);
+ while (tv_ms_le2(&t->expire, &now))
+ tv_ms_add(&t->expire, &t->expire, s->inter);
goto new_chk;
}
- else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
+ else if (s->result < 0 || tv_ms_le2(&t->expire, &now)) {
//fprintf(stderr, "process_chk: 10\n");
/* failure or timeout detected */
if (s->health > s->rise) {
set_server_down(s);
s->curfd = -1;
fd_delete(fd);
- while (tv_cmp2_ms(&t->expire, &now) <= 0)
- tv_delayfrom(&t->expire, &t->expire, s->inter);
+ while (tv_ms_le2(&t->expire, &now))
+ tv_ms_add(&t->expire, &t->expire, s->inter);
goto new_chk;
}
/* if result is 0 and there's no timeout, we have to wait again */
//fprintf(stderr, "process_chk: 11\n");
s->result = 0;
task_queue(t); /* restore t to its place in the task list */
- return tv_remain2(&now, &t->expire);
+ return tv_ms_remain2(&now, &t->expire);
}
if (s->fe->clitimeout) {
if (EV_FD_ISSET(cfd, DIR_RD))
- tv_delayfrom(&s->req->rex, &now, s->fe->clitimeout);
+ tv_ms_add(&s->req->rex, &now, s->fe->clitimeout);
if (EV_FD_ISSET(cfd, DIR_WR))
- tv_delayfrom(&s->rep->wex, &now, s->fe->clitimeout);
+ tv_ms_add(&s->rep->wex, &now, s->fe->clitimeout);
}
tv_min(&t->expire, &s->req->rex, &s->rep->wex);
qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
"cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
"req=%d, rep=%d, clifd=%d\n",
- s, tv_remain(&now, &t->expire),
+ s, tv_ms_remain(&now, &t->expire),
s->cli_state,
s->srv_state,
EV_FD_ISSET(s->cli_fd, DIR_RD),
EV_FD_SET(s->cli_fd, DIR_WR);
tv_eternity(&s->req->rex);
if (s->fe->clitimeout)
- tv_delayfrom(&s->rep->wex, &now, s->fe->clitimeout);
+ tv_ms_add(&s->rep->wex, &now, s->fe->clitimeout);
else
tv_eternity(&s->rep->wex);
s->cli_state = CL_STSHUTR;
/* DEBUG code : this should never ever happen, otherwise it indicates
* that a task still has something to do and will provoke a quick loop.
*/
- if (tv_remain2(&now, &t->expire) <= 0)
+ if (tv_ms_remain2(&now, &t->expire) <= 0)
exit(100);
#endif
- return tv_remain2(&now, &t->expire); /* nothing more to do */
+ return tv_ms_remain2(&now, &t->expire); /* nothing more to do */
}
s->fe->feconn--;
write(1, trash, len);
}
- s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
+ s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
if (s->req != NULL)
s->logs.bytes_in = s->req->total;
if (s->rep != NULL)
}
/* 3: has the read timeout expired ? */
- else if (unlikely(tv_cmp2_le(&req->rex, &now))) {
+ else if (unlikely(tv_ms_le2(&req->rex, &now))) {
/* read timeout : give up with an error message. */
txn->status = 408;
client_retnclose(t, error_message(t, HTTP_ERR_408));
* req->l == rlim-data
*/
if (t->fe->clitimeout)
- tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
+ tv_ms_add(&req->rex, &now, t->fe->clitimeout);
else
tv_eternity(&req->rex);
}
/* no need to go further */
txn->status = 403;
/* let's log the request time */
- t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
+ t->logs.t_request = tv_ms_elapsed(&t->logs.tv_accept, &now);
client_retnclose(t, error_message(t, HTTP_ERR_403));
goto return_prx_cond;
}
t->cli_state = CL_STDATA;
req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
- t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
+ t->logs.t_request = tv_ms_elapsed(&t->logs.tv_accept, &now);
if (!t->fe->clitimeout ||
(t->srv_state < SV_STDATA && t->be->srvtimeout)) {
/* flush the request so that we can drop the connection early
* if the client closes first.
*/
- tv_delayfrom(&req->cex, &now,
+ tv_ms_add(&req->cex, &now,
t->be->contimeout ? t->be->contimeout : 0);
}
* to shutw */
EV_FD_SET(t->cli_fd, DIR_RD);
if (t->fe->clitimeout)
- tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
+ tv_ms_add(&req->rex, &now, t->fe->clitimeout);
t->cli_state = CL_STSHUTW;
//fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
return 1;
}
/* read timeout */
- else if (tv_cmp2_le(&req->rex, &now)) {
+ else if (tv_ms_le2(&req->rex, &now)) {
EV_FD_CLR(t->cli_fd, DIR_RD);
tv_eternity(&req->rex);
t->cli_state = CL_STSHUTR;
return 1;
}
/* write timeout */
- else if (tv_cmp2_le(&rep->wex, &now)) {
+ else if (tv_ms_le2(&rep->wex, &now)) {
EV_FD_CLR(t->cli_fd, DIR_WR);
tv_eternity(&rep->wex);
shutdown(t->cli_fd, SHUT_WR);
* to shutw */
EV_FD_SET(t->cli_fd, DIR_RD);
if (t->fe->clitimeout)
- tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
+ tv_ms_add(&req->rex, &now, t->fe->clitimeout);
t->cli_state = CL_STSHUTW;
if (!(t->flags & SN_ERR_MASK))
*/
tv_eternity(&req->rex);
else
- tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
+ tv_ms_add(&req->rex, &now, t->fe->clitimeout);
}
}
if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
/* restart writing */
if (t->fe->clitimeout) {
- tv_delayfrom(&rep->wex, &now, t->fe->clitimeout);
+ tv_ms_add(&rep->wex, &now, t->fe->clitimeout);
/* FIXME: to prevent the client from expiring read timeouts during writes,
* we refresh it. */
req->rex = rep->wex;
t->cli_state = CL_STCLOSE;
return 1;
}
- else if (tv_cmp2_le(&rep->wex, &now)) {
+ else if (tv_ms_le2(&rep->wex, &now)) {
tv_eternity(&rep->wex);
fd_delete(t->cli_fd);
t->cli_state = CL_STCLOSE;
if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
/* restart writing */
if (t->fe->clitimeout) {
- tv_delayfrom(&rep->wex, &now, t->fe->clitimeout);
+ tv_ms_add(&rep->wex, &now, t->fe->clitimeout);
/* FIXME: to prevent the client from expiring read timeouts during writes,
* we refresh it. */
req->rex = rep->wex;
t->cli_state = CL_STCLOSE;
return 1;
}
- else if (tv_cmp2_le(&req->rex, &now)) {
+ else if (tv_ms_le2(&req->rex, &now)) {
tv_eternity(&req->rex);
fd_delete(t->cli_fd);
t->cli_state = CL_STCLOSE;
/* there's still some space in the buffer */
if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
if (t->fe->clitimeout)
- tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
+ tv_ms_add(&req->rex, &now, t->fe->clitimeout);
else
tv_eternity(&req->rex);
//fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
(t->req->l == 0 || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
tv_eternity(&req->cex);
if (t->pend_pos)
- t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
+ t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
/* note that this must not return any error because it would be able to
* overwrite the client_retnclose() output.
*/
* already set the connect expiration date to the right
* timeout. We just have to check that it has not expired.
*/
- if (!tv_cmp2_le(&req->cex, &now))
+ if (!tv_ms_le2(&req->cex, &now))
return 0;
/* We will set the queue timer to the time spent, just for
* the tarpitted connections by filtering on the 'PT' status flags.
*/
tv_eternity(&req->cex);
- t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
+ t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
500, error_message(t, HTTP_ERR_500));
return 1;
* to any other session to release it and wake us up again.
*/
if (t->pend_pos) {
- if (!tv_cmp2_le(&req->cex, &now))
+ if (!tv_ms_le2(&req->cex, &now))
return 0;
else {
/* we've been waiting too long here */
tv_eternity(&req->cex);
- t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
+ t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
503, error_message(t, HTTP_ERR_503));
if (t->srv)
* number of retries.
*/
if (srv_retryable_connect(t)) {
- t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
+ t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
return t->srv_state != SV_STIDLE;
}
} while (1);
srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
return 1;
}
- if (!(req->flags & BF_WRITE_STATUS) && !tv_cmp2_le(&req->cex, &now)) {
+ if (!(req->flags & BF_WRITE_STATUS) && !tv_ms_le2(&req->cex, &now)) {
//fprintf(stderr,"1: c=%d, s=%d, now=%d.%06d, exp=%d.%06d\n", c, s, now.tv_sec, now.tv_usec, req->cex.tv_sec, req->cex.tv_usec);
return 0; /* nothing changed */
}
* the SV_STIDLE state.
*/
if (srv_retryable_connect(t)) {
- t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
+ t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
return t->srv_state != SV_STCONN;
}
} while (1);
}
else { /* no error or write 0 */
- t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
+ t->logs.t_connect = tv_ms_elapsed(&t->logs.tv_accept, &now);
//fprintf(stderr,"3: c=%d, s=%d\n", c, s);
if (req->l == 0) /* nothing to write */ {
} else /* need the right to write */ {
EV_FD_SET(t->srv_fd, DIR_WR);
if (t->be->srvtimeout) {
- tv_delayfrom(&req->wex, &now, t->be->srvtimeout);
+ tv_ms_add(&req->wex, &now, t->be->srvtimeout);
/* FIXME: to prevent the server from expiring read timeouts during writes,
* we refresh it. */
rep->rex = req->wex;
if (t->be->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
EV_FD_SET(t->srv_fd, DIR_RD);
if (t->be->srvtimeout)
- tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
+ tv_ms_add(&rep->rex, &now, t->be->srvtimeout);
else
tv_eternity(&rep->rex);
* rep->l == rlim-data
*/
if (t->be->srvtimeout)
- tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
+ tv_ms_add(&rep->rex, &now, t->be->srvtimeout);
else
tv_eternity(&rep->rex);
}
/* read timeout : return a 504 to the client.
*/
else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_RD) &&
- tv_cmp2_le(&rep->rex, &now))) {
+ tv_ms_le2(&rep->rex, &now))) {
tv_eternity(&rep->rex);
tv_eternity(&req->wex);
fd_delete(t->srv_fd);
* alive when switching to shutw */
EV_FD_SET(t->srv_fd, DIR_RD);
if (t->be->srvtimeout)
- tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
+ tv_ms_add(&rep->rex, &now, t->be->srvtimeout);
shutdown(t->srv_fd, SHUT_WR);
t->srv_state = SV_STSHUTW;
* some work to do on the headers.
*/
else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_WR) &&
- tv_cmp2_le(&req->wex, &now))) {
+ tv_ms_le2(&req->wex, &now))) {
EV_FD_CLR(t->srv_fd, DIR_WR);
tv_eternity(&req->wex);
shutdown(t->srv_fd, SHUT_WR);
* when switching to shutw */
EV_FD_SET(t->srv_fd, DIR_RD);
if (t->be->srvtimeout)
- tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
+ tv_ms_add(&rep->rex, &now, t->be->srvtimeout);
t->srv_state = SV_STSHUTW;
if (!(t->flags & SN_ERR_MASK))
if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
/* restart writing */
if (t->be->srvtimeout) {
- tv_delayfrom(&req->wex, &now, t->be->srvtimeout);
+ tv_ms_add(&req->wex, &now, t->be->srvtimeout);
/* FIXME: to prevent the server from expiring read timeouts during writes,
* we refresh it. */
rep->rex = req->wex;
t->srv_state = SV_STDATA;
rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
- t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
+ t->logs.t_data = tv_ms_elapsed(&t->logs.tv_accept, &now);
/* client connection already closed or option 'forceclose' required :
* we close the server's outgoing connection right now.
* to shutw */
EV_FD_SET(t->srv_fd, DIR_RD);
if (t->be->srvtimeout)
- tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
+ tv_ms_add(&rep->rex, &now, t->be->srvtimeout);
shutdown(t->srv_fd, SHUT_WR);
t->srv_state = SV_STSHUTW;
* to shutw */
EV_FD_SET(t->srv_fd, DIR_RD);
if (t->be->srvtimeout)
- tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
+ tv_ms_add(&rep->rex, &now, t->be->srvtimeout);
t->srv_state = SV_STSHUTW;
return 1;
}
/* read timeout */
- else if (tv_cmp2_le(&rep->rex, &now)) {
+ else if (tv_ms_le2(&rep->rex, &now)) {
EV_FD_CLR(t->srv_fd, DIR_RD);
tv_eternity(&rep->rex);
t->srv_state = SV_STSHUTR;
return 1;
}
/* write timeout */
- else if (tv_cmp2_le(&req->wex, &now)) {
+ else if (tv_ms_le2(&req->wex, &now)) {
EV_FD_CLR(t->srv_fd, DIR_WR);
tv_eternity(&req->wex);
shutdown(t->srv_fd, SHUT_WR);
* to shutw */
EV_FD_SET(t->srv_fd, DIR_RD);
if (t->be->srvtimeout)
- tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
+ tv_ms_add(&rep->rex, &now, t->be->srvtimeout);
t->srv_state = SV_STSHUTW;
if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_SRVTO;
if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
/* restart writing */
if (t->be->srvtimeout) {
- tv_delayfrom(&req->wex, &now, t->be->srvtimeout);
+ tv_ms_add(&req->wex, &now, t->be->srvtimeout);
/* FIXME: to prevent the server from expiring read timeouts during writes,
* we refresh it. */
rep->rex = req->wex;
else {
if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
if (t->be->srvtimeout)
- tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
+ tv_ms_add(&rep->rex, &now, t->be->srvtimeout);
else
tv_eternity(&rep->rex);
}
return 1;
}
- else if (tv_cmp2_le(&req->wex, &now)) {
+ else if (tv_ms_le2(&req->wex, &now)) {
//EV_FD_CLR(t->srv_fd, DIR_WR);
tv_eternity(&req->wex);
fd_delete(t->srv_fd);
if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
/* restart writing */
if (t->be->srvtimeout) {
- tv_delayfrom(&req->wex, &now, t->be->srvtimeout);
+ tv_ms_add(&req->wex, &now, t->be->srvtimeout);
/* FIXME: to prevent the server from expiring read timeouts during writes,
* we refresh it. */
rep->rex = req->wex;
return 1;
}
- else if (tv_cmp2_le(&rep->rex, &now)) {
+ else if (tv_ms_le2(&rep->rex, &now)) {
//EV_FD_CLR(t->srv_fd, DIR_RD);
tv_eternity(&rep->rex);
fd_delete(t->srv_fd);
else {
if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
if (t->be->srvtimeout)
- tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
+ tv_ms_add(&rep->rex, &now, t->be->srvtimeout);
else
tv_eternity(&rep->rex);
}
}/* end while(srv) */
}/* end else if server == NULL */
- tv_delayfrom(&asession_temp->expire, &now, t->be->appsession_timeout);
+ tv_ms_add(&asession_temp->expire, &now, t->be->appsession_timeout);
}/* end if ((t->proxy->appsession_name != NULL) ... */
}
if (asession_temp->serverid[0] == '\0')
memcpy(asession_temp->serverid, t->srv->id, server_id_len);
- tv_delayfrom(&asession_temp->expire, &now, t->be->appsession_timeout);
+ tv_ms_add(&asession_temp->expire, &now, t->be->appsession_timeout);
#if defined(DEBUG_HASH)
print_table(&(t->be->htbl_proxy));
pool_free_to(apools.sessid, local_asession.sessid);
}
- tv_delayfrom(&asession_temp->expire, &now, t->be->appsession_timeout);
+ tv_ms_add(&asession_temp->expire, &now, t->be->appsession_timeout);
asession_temp->request_count++;
#if defined(DEBUG_HASH)
*/
t->cli_state = CL_STSHUTR;
t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */
- t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
+ t->logs.t_request = tv_ms_elapsed(&t->logs.tv_accept, &now);
t->data_source = DATA_SRC_STATS;
t->data_state = DATA_ST_INIT;
produce_content(t);
while (p) {
if (p->state != PR_STSTOPPED) {
int t;
- t = tv_remain2(&now, &p->stop_time);
+ t = tv_ms_remain2(&now, &p->stop_time);
if (t == 0) {
Warning("Proxy %s stopped.\n", p->id);
send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
if (p->state != PR_STSTOPPED) {
Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
- tv_delayfrom(&p->stop_time, &now, p->grace);
+ tv_ms_add(&p->stop_time, &now, p->grace);
}
p = p->next;
}
if (b->flags & BF_READ_STATUS) {
out_wakeup:
if (b->rto && EV_FD_ISSET(fd, DIR_RD))
- tv_delayfrom(&b->rex, &now, b->rto);
+ tv_ms_add(&b->rex, &now, b->rto);
else
tv_eternity(&b->rex);
if (b->flags & BF_WRITE_STATUS) {
if (b->wto) {
- tv_delayfrom(&b->wex, &now, b->wto);
+ tv_ms_add(&b->wex, &now, b->wto);
/* FIXME: to prevent the client from expiring read timeouts during writes,
* we refresh it. A solution would be to merge read+write timeouts into a
* unique one, although that needs some study particularly on full-duplex
if (likely(timer_wq.data != NULL)) {
task = LIST_ELEM(timer_wq.data, struct task *, qlist);
- if (likely(tv_cmp_ge(&task->expire, &now) > 0))
- return tv_remain(&now, &task->expire);
+ if (likely(__tv_isge(&task->expire, &now) > 0))
+ return tv_ms_remain(&now, &task->expire);
}
/* OK we lose. Let's scan the tree then. */
tree64_foreach(&timer_wq, data, stack, slen) {
task = LIST_ELEM(data, struct task *, qlist);
- if (!tv_isbefore(&task->expire, &now)) {
- next_time = tv_remain(&now, &task->expire);
+ if (__tv_isgt(&task->expire, &now)) {
+ next_time = tv_ms_remain(&now, &task->expire);
break;
}
/*
* Time calculation functions.
*
- * Copyright 2000-2006 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
/*
* adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
*/
-REGPRM3 struct timeval *tv_delayfrom(struct timeval *tv, const struct timeval *from, int ms)
+REGPRM3 struct timeval *_tv_ms_add(struct timeval *tv, const struct timeval *from, int ms)
{
- if (!tv || !from)
- return NULL;
- tv->tv_usec = from->tv_usec + (ms%1000)*1000;
- tv->tv_sec = from->tv_sec + (ms/1000);
+ tv->tv_usec = from->tv_usec + (ms % 1000) * 1000;
+ tv->tv_sec = from->tv_sec + (ms / 1000);
while (tv->tv_usec >= 1000000) {
tv->tv_usec -= 1000000;
tv->tv_sec++;
/*
* compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
- * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
+ * Must not be used when either argument is eternity. Use tv_ms_cmp2() for that.
*/
-REGPRM2 int tv_cmp_ms(const struct timeval *tv1, const struct timeval *tv2)
+REGPRM2 int _tv_ms_cmp(const struct timeval *tv1, const struct timeval *tv2)
{
- if ((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec) {
- if ((unsigned)tv2->tv_usec >= (unsigned)tv1->tv_usec + 1000)
- return -1;
- else if ((unsigned)tv1->tv_usec >= (unsigned)tv2->tv_usec + 1000)
- return 1;
- else
- return 0;
- }
- else if (((unsigned)tv2->tv_sec > (unsigned)tv1->tv_sec + 1) ||
- (((unsigned)tv2->tv_sec == (unsigned)tv1->tv_sec + 1) &&
- ((unsigned)tv2->tv_usec + 1000000 >= (unsigned)tv1->tv_usec + 1000)))
- return -1;
- else if (((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec + 1) ||
- (((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec + 1) &&
- ((unsigned)tv1->tv_usec + 1000000 >= (unsigned)tv2->tv_usec + 1000)))
- return 1;
- else
- return 0;
+ return __tv_ms_cmp(tv1, tv2);
}
/*
* compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
* assuming that TV_ETERNITY is greater than everything.
*/
-REGPRM2 int tv_cmp2_ms(const struct timeval *tv1, const struct timeval *tv2)
+REGPRM2 int _tv_ms_cmp2(const struct timeval *tv1, const struct timeval *tv2)
{
- if (tv_iseternity(tv1))
- if (tv_iseternity(tv2))
- return 0; /* same */
- else
- return 1; /* tv1 later than tv2 */
- else if (tv_iseternity(tv2))
- return -1; /* tv2 later than tv1 */
-
- if ((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec) {
- if ((unsigned)tv1->tv_usec >= (unsigned)tv2->tv_usec + 1000)
- return 1;
- else if ((unsigned)tv2->tv_usec >= (unsigned)tv1->tv_usec + 1000)
- return -1;
- else
- return 0;
- }
- else if (((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec + 1) ||
- (((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec + 1) &&
- ((unsigned)tv1->tv_usec + 1000000 >= (unsigned)tv2->tv_usec + 1000)))
- return 1;
- else if (((unsigned)tv2->tv_sec > (unsigned)tv1->tv_sec + 1) ||
- (((unsigned)tv2->tv_sec == (unsigned)tv1->tv_sec + 1) &&
- ((unsigned)tv2->tv_usec + 1000000 >= (unsigned)tv1->tv_usec + 1000)))
- return -1;
- else
- return 0;
+ return __tv_ms_cmp2(tv1, tv2);
}
/*
* compares <tv1> and <tv2> modulo 1 ms: returns 1 if tv1 <= tv2, 0 if tv1 > tv2,
* assuming that TV_ETERNITY is greater than everything. Returns 0 if tv1 is
* TV_ETERNITY, and always assumes that tv2 != TV_ETERNITY. Designed to replace
- * occurrences of (tv_cmp2_ms(tv,now) <= 0).
+ * occurrences of (tv_ms_cmp2(tv,now) <= 0).
*/
-REGPRM2 int tv_cmp2_le(const struct timeval *tv1, const struct timeval *tv2)
+REGPRM2 int _tv_ms_le2(const struct timeval *tv1, const struct timeval *tv2)
{
- if (likely((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec + 1))
- return 0;
-
- if (likely((unsigned)tv1->tv_sec < (unsigned)tv2->tv_sec))
- return 1;
-
- if (likely((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec)) {
- if ((unsigned)tv2->tv_usec >= (unsigned)tv1->tv_usec + 1000)
- return 1;
- else
- return 0;
- }
+ return __tv_ms_le2(tv1, tv2);
+}
- if (unlikely(((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec + 1) &&
- ((unsigned)tv1->tv_usec + 1000000 >= (unsigned)tv2->tv_usec + 1000)))
- return 0;
- else
- return 1;
+/*
+ * returns the remaining time between tv1=now and event=tv2
+ * if tv2 is passed, 0 is returned.
+ * Must not be used when either argument is eternity.
+ */
+REGPRM2 unsigned long _tv_ms_remain(const struct timeval *tv1, const struct timeval *tv2)
+{
+ return __tv_ms_remain(tv1, tv2);
}
/*
* if tv2 is passed, 0 is returned.
* Returns TIME_ETERNITY if tv2 is eternity.
*/
-REGPRM2 unsigned long tv_remain2(const struct timeval *tv1, const struct timeval *tv2)
+REGPRM2 unsigned long _tv_ms_remain2(const struct timeval *tv1, const struct timeval *tv2)
{
- unsigned long ret;
-
if (tv_iseternity(tv2))
return TIME_ETERNITY;
- if (tv_cmp_ms(tv1, tv2) >= 0)
- return 0; /* event elapsed */
-
- ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
- if ((unsigned)tv2->tv_usec > (unsigned)tv1->tv_usec)
- ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
- else
- ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
- return (unsigned long) ret;
+ return __tv_ms_remain(tv1, tv2);
}
-
/*
- * returns the absolute difference, in ms, between tv1 and tv2
+ * Returns the time in ms elapsed between tv1 and tv2, assuming that tv1<=tv2.
* Must not be used when either argument is eternity.
*/
-REGPRM2 unsigned long tv_delta(const struct timeval *tv1, const struct timeval *tv2)
+REGPRM2 unsigned long _tv_ms_elapsed(const struct timeval *tv1, const struct timeval *tv2)
{
- int cmp;
- unsigned long ret;
-
-
- cmp = tv_cmp(tv1, tv2);
- if (!cmp)
- return 0; /* same dates, null diff */
- else if (cmp < 0) {
- const struct timeval *tmp = tv1;
- tv1 = tv2;
- tv2 = tmp;
- }
- ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
- if ((unsigned)tv1->tv_usec > (unsigned)tv2->tv_usec)
- ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
- else
- ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
- return (unsigned long) ret;
+ return __tv_ms_elapsed(tv1, tv2);
}
/*