From: Willy Tarreau Date: Sat, 12 May 2007 20:35:00 +0000 (+0200) Subject: [MAJOR] replaced all timeouts with struct timeval X-Git-Tag: v1.3.11~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d825eef9c5c55b2252b4386bf5e5f03069e9088a;p=thirdparty%2Fhaproxy.git [MAJOR] replaced all timeouts with struct timeval The timeout functions were difficult to manipulate because they were rounding results to the millisecond. Thus, it was difficult to compare and to check what expired and what did not. Also, the comparison functions were heavy with multiplies and divides by 1000. Now, all timeouts are stored in timevals, reducing the number of operations for updates and leading to cleaner and more efficient code. --- diff --git a/include/common/appsession.h b/include/common/appsession.h index eb9ba2d0ff..8fa681cae1 100644 --- a/include/common/appsession.h +++ b/include/common/appsession.h @@ -44,7 +44,7 @@ void destroy(void *data); static void print_table(const CHTbl *htbl); #endif -int appsession_refresh(struct task *t); +void appsession_refresh(struct task *t, struct timeval *next); int appsession_task_init(void); int appsession_init(void); void appsession_cleanup(void); diff --git a/include/proto/checks.h b/include/proto/checks.h index 6ac32a1c9c..839af55a53 100644 --- a/include/proto/checks.h +++ b/include/proto/checks.h @@ -2,7 +2,7 @@ include/proto/checks.h Functions prototypes for the checks. - 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 @@ -25,7 +25,7 @@ #include #include -int process_chk(struct task *t); +void process_chk(struct task *t, struct timeval *next); #endif /* _PROTO_CHECKS_H */ diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h index 298d30d074..da4ea0e94e 100644 --- a/include/proto/proto_http.h +++ b/include/proto/proto_http.h @@ -58,7 +58,7 @@ extern const char http_is_ver_token[256]; #define HTTP_IS_VER_TOKEN(x) (http_is_ver_token[(unsigned char)(x)]) int event_accept(int fd); -int process_session(struct task *t); +void process_session(struct task *t, struct timeval *next); int process_cli(struct session *t); int process_srv(struct session *t); diff --git a/include/proto/proxy.h b/include/proto/proxy.h index 3fa541a2db..38d7325cc3 100644 --- a/include/proto/proxy.h +++ b/include/proto/proxy.h @@ -2,7 +2,7 @@ include/proto/proxy.h This file defines function prototypes for proxy management. - 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 @@ -23,10 +23,11 @@ #define _PROTO_PROXY_H #include +#include #include int start_proxies(int verbose); -int maintain_proxies(void); +void maintain_proxies(struct timeval *next); void soft_stop(void); void pause_proxy(struct proxy *p); void pause_proxies(void); diff --git a/include/proto/queue.h b/include/proto/queue.h index c113f0352f..4370cb39d8 100644 --- a/include/proto/queue.h +++ b/include/proto/queue.h @@ -2,7 +2,7 @@ include/proto/queue.h This file defines everything related to queues. - 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 @@ -35,7 +35,7 @@ struct session *pendconn_get_next_sess(struct server *srv, struct proxy *px); struct pendconn *pendconn_add(struct session *sess); void pendconn_free(struct pendconn *p); -int process_srv_queue(struct task *t); +void process_srv_queue(struct task *t, struct timeval *next); unsigned int srv_dynamic_maxconn(const struct server *s); diff --git a/include/proto/task.h b/include/proto/task.h index 2c724ad61f..c594d525ed 100644 --- a/include/proto/task.h +++ b/include/proto/task.h @@ -111,12 +111,10 @@ struct task *task_queue(struct task *task); * - wake up all expired tasks * - call all runnable tasks * - call maintain_proxies() to enable/disable the listeners - * - return the delay till next event in ms, -1 = wait indefinitely - * Note: this part should be rewritten with the O(ln(n)) scheduler. - * + * - return the date of next event in or eternity. */ -int process_runnable_tasks(); +void process_runnable_tasks(struct timeval *next); #endif /* _PROTO_TASK_H */ diff --git a/include/types/buffers.h b/include/types/buffers.h index 4afc293e3c..9b781b8421 100644 --- a/include/types/buffers.h +++ b/include/types/buffers.h @@ -63,9 +63,9 @@ struct buffer { struct timeval rex; /* expiration date for a read */ struct timeval wex; /* expiration date for a write */ struct timeval cex; /* expiration date for a connect */ - int rto; /* read timeout */ - int wto; /* write timeout */ - int cto; /* connect timeout */ + struct timeval rto; /* read timeout */ + struct timeval wto; /* write timeout */ + struct timeval cto; /* connect timeout */ unsigned int l; /* data length */ char *r, *w, *lr; /* read ptr, write ptr, last read */ char *rlim; /* read limit, used for header rewriting */ diff --git a/include/types/fd.h b/include/types/fd.h index 392c94ee74..a1b6e9d4d4 100644 --- a/include/types/fd.h +++ b/include/types/fd.h @@ -81,7 +81,7 @@ struct fdtab { * it returns 0. It may be the same as clr(). * - clo() should be used to do indicate the poller that fd will be closed. It * may be the same as rem() on some pollers. - * - poll() calls the poller, waiting at most wait_time ms. + * - poll() calls the poller, expiring at */ struct poller { void *private; /* any private data for the poller */ @@ -92,7 +92,7 @@ struct poller { int REGPRM2 (*cond_c)(const int fd, int dir); /* clear polling on for if set */ void REGPRM1 (*rem)(const int fd); /* remove any polling on */ void REGPRM1 (*clo)(const int fd); /* mark as closed */ - void REGPRM2 (*poll)(struct poller *p, int wait_time); /* the poller itself */ + void REGPRM2 (*poll)(struct poller *p, struct timeval *exp); /* the poller itself */ int REGPRM1 (*init)(struct poller *p); /* poller initialization */ void REGPRM1 (*term)(struct poller *p); /* termination of this poller */ int REGPRM1 (*test)(struct poller *p); /* pre-init check of the poller */ diff --git a/include/types/proxy.h b/include/types/proxy.h index c403e59f4c..532348ec9a 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -96,7 +96,6 @@ struct proxy { char *appsession_name; /* name of the cookie to look for */ int appsession_name_len; /* strlen(appsession_name), computed only once */ int appsession_len; /* length of the appsession cookie value to be used */ - int appsession_timeout; CHTbl htbl_proxy; /* Per Proxy hashtable */ char *capture_name; /* beginning of the name of the cookie to capture */ int capture_namelen; /* length of the cookie name to match */ @@ -104,9 +103,10 @@ struct proxy { struct uri_auth *uri_auth; /* if non-NULL, the (list of) per-URI authentications */ char *monitor_uri; /* a special URI to which we respond with HTTP/200 OK */ int monitor_uri_len; /* length of the string above. 0 if unused */ - int clitimeout; /* client I/O timeout (in milliseconds) */ - int srvtimeout; /* server I/O timeout (in milliseconds) */ - int contimeout; /* connect timeout (in milliseconds) */ + struct timeval clitimeout; /* client I/O timeout (in milliseconds) */ + struct timeval srvtimeout; /* server I/O timeout (in milliseconds) */ + struct timeval contimeout; /* connect timeout (in milliseconds) */ + struct timeval appsession_timeout; char *id; /* proxy id */ struct list pendconns; /* pending connections with no server assigned yet */ int nbpend, nbpend_max; /* number of pending connections with no server assigned yet */ diff --git a/include/types/task.h b/include/types/task.h index 1fd78be56b..42699dbfff 100644 --- a/include/types/task.h +++ b/include/types/task.h @@ -2,7 +2,7 @@ include/types/task.h Macros, variables and structures for task management. - 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 @@ -38,7 +38,7 @@ struct task { struct ultree *wq; /* NULL if unqueued, or back ref to the carrier node in the WQ */ int state; /* task state : IDLE or RUNNING */ struct timeval expire; /* next expiration time for this task, use only for fast sorting */ - int (*process)(struct task *t); /* the function which processes the task */ + void (*process)(struct task *t, struct timeval *next); /* the function which processes the task */ void *context; /* the task's context */ }; diff --git a/src/appsession.c b/src/appsession.c index d11fb19507..0307ff7c4a 100644 --- a/src/appsession.c +++ b/src/appsession.c @@ -125,7 +125,7 @@ int appsession_task_init(void) return 0; } -int appsession_refresh(struct task *t) +void appsession_refresh(struct task *t, struct timeval *next) { struct proxy *p = proxy; CHTbl *htbl; @@ -143,7 +143,7 @@ int appsession_refresh(struct task *t) for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) { asession = (appsess *)list_data(element); - if (tv_ms_le2(&asession->expire, &now)) { + if (__tv_isle(&asession->expire, &now)) { if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) { int len; @@ -165,7 +165,7 @@ int appsession_refresh(struct task *t) } else element = last; - }/* end if (tv_ms_le2(&asession->expire, &now)) */ + }/* end if (__tv_isle(&asession->expire, &now)) */ else last = element; }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */ @@ -174,7 +174,7 @@ int appsession_refresh(struct task *t) p = p->next; } tv_ms_add(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */ - return TBLCHKINT; + *next = t->expire; } /* end appsession_refresh */ int match_str(const void *key1, const void *key2) diff --git a/src/backend.c b/src/backend.c index 69e79d408d..002394ea4c 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1,7 +1,7 @@ /* * Backend variables and functions. * - * Copyright 2000-2006 Willy Tarreau + * Copyright 2000-2007 Willy Tarreau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -550,8 +550,8 @@ int connect_server(struct session *s) s->srv->cur_sess_max = s->srv->cur_sess; } - if (s->be->contimeout) - tv_ms_add(&s->req->cex, &now, s->be->contimeout); + if (tv_isset(&s->be->contimeout)) + tv_add(&s->req->cex, &now, &s->be->contimeout); else tv_eternity(&s->req->cex); return SN_ERR_NONE; /* connection is OK */ @@ -680,8 +680,8 @@ int srv_redispatch_connect(struct session *t) case SRV_STATUS_QUEUED: /* FIXME-20060503 : we should use the queue timeout instead */ - if (t->be->contimeout) - tv_ms_add(&t->req->cex, &now, t->be->contimeout); + if (tv_isset(&t->be->contimeout)) + tv_add(&t->req->cex, &now, &t->be->contimeout); else tv_eternity(&t->req->cex); t->srv_state = SV_STIDLE; diff --git a/src/cfgparse.c b/src/cfgparse.c index b2e76b310f..1edaa8fc0b 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -766,7 +766,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args) curproxy->appsession_name = strdup(args[1]); curproxy->appsession_name_len = strlen(curproxy->appsession_name); curproxy->appsession_len = atoi(args[3]); - curproxy->appsession_timeout = atoi(args[5]); + __tv_from_ms(&curproxy->appsession_timeout, atoi(args[5])); rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy); if (rc) { Alert("Error Init Appsession Hashtable.\n"); @@ -857,7 +857,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args) } } else if (!strcmp(args[0], "contimeout")) { /* connect timeout */ - if (curproxy->contimeout != defproxy.contimeout) { + if (!__tv_iseq(&curproxy->contimeout, &defproxy.contimeout)) { Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]); return 0; } @@ -869,10 +869,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args) file, linenum, args[0]); return -1; } - curproxy->contimeout = atol(args[1]); + __tv_from_ms(&curproxy->contimeout, atol(args[1])); } else if (!strcmp(args[0], "clitimeout")) { /* client timeout */ - if (curproxy->clitimeout != defproxy.clitimeout) { + if (!__tv_iseq(&curproxy->clitimeout, &defproxy.clitimeout)) { Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]); return 0; @@ -885,10 +885,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args) file, linenum, args[0]); return -1; } - curproxy->clitimeout = atol(args[1]); + __tv_from_ms(&curproxy->clitimeout, atol(args[1])); } else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */ - if (curproxy->srvtimeout != defproxy.srvtimeout) { + if (!__tv_iseq(&curproxy->srvtimeout, &defproxy.srvtimeout)) { Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]); return 0; } @@ -900,7 +900,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args) file, linenum, args[0]); return -1; } - curproxy->srvtimeout = atol(args[1]); + __tv_from_ms(&curproxy->srvtimeout, atol(args[1])); } else if (!strcmp(args[0], "retries")) { /* connection retries */ if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) @@ -2385,8 +2385,9 @@ int readcfgfile(const char *file) } } if ((curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HTTP) && - (((curproxy->cap & PR_CAP_FE) && !curproxy->clitimeout) || - ((curproxy->cap & PR_CAP_BE) && (curproxy->srv) && (!curproxy->contimeout || !curproxy->srvtimeout)))) { + (((curproxy->cap & PR_CAP_FE) && !tv_isset(&curproxy->clitimeout)) || + ((curproxy->cap & PR_CAP_BE) && (curproxy->srv) && + (!tv_isset(&curproxy->contimeout) || !tv_isset(&curproxy->srvtimeout))))) { Warning("parsing %s : missing timeouts for %s '%s'.\n" " | While not properly invalid, you will certainly encounter various problems\n" " | with such a configuration. To fix this, please ensure that all following\n" diff --git a/src/checks.c b/src/checks.c index 83a539eea1..96f5895f6c 100644 --- a/src/checks.c +++ b/src/checks.c @@ -1,7 +1,7 @@ /* * Health-checks functions. * - * Copyright 2000-2006 Willy Tarreau + * Copyright 2000-2007 Willy Tarreau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -275,13 +275,12 @@ static int event_srv_chk_r(int fd) * manages a server health-check. Returns * the time the task accepts to wait, or TIME_ETERNITY for infinity. */ -int process_chk(struct task *t) +void process_chk(struct task *t, struct timeval *next) { __label__ new_chk, out; struct server *s = t->context; struct sockaddr_in sa; int fd; - int next_time; //fprintf(stderr, "process_chk: task=%p\n", t); @@ -289,9 +288,9 @@ int process_chk(struct task *t) fd = s->curfd; if (fd < 0) { /* no check currently running */ //fprintf(stderr, "process_chk: 2\n"); - if (!tv_ms_le2(&t->expire, &now)) { /* not good time yet */ + if (!__tv_isle(&t->expire, &now)) { /* not good time yet */ task_queue(t); /* restore t to its place in the task list */ - next_time = tv_ms_remain2(&now, &t->expire); + *next = t->expire; goto out; } @@ -299,10 +298,10 @@ int process_chk(struct task *t) * the server should not be checked. */ if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) { - while (tv_ms_le2(&t->expire, &now)) + while (__tv_isle(&t->expire, &now)) tv_ms_add(&t->expire, &t->expire, s->inter); task_queue(t); /* restore t to its place in the task list */ - next_time = tv_ms_remain2(&now, &t->expire); + *next = t->expire; goto out; } @@ -410,7 +409,7 @@ int process_chk(struct task *t) /* FIXME: we allow up to for a connection to establish, but we should use another parameter */ tv_ms_add(&t->expire, &now, s->inter); task_queue(t); /* restore t to its place in the task list */ - return tv_ms_remain(&now, &t->expire); + *next = t->expire; } else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) { s->result = -1; /* a real error */ @@ -422,7 +421,7 @@ int process_chk(struct task *t) if (!s->result) { /* nothing done */ //fprintf(stderr, "process_chk: 6\n"); - while (tv_ms_le2(&t->expire, &now)) + while (__tv_isle(&t->expire, &now)) tv_ms_add(&t->expire, &t->expire, s->inter); goto new_chk; /* may be we should initialize a new check */ } @@ -437,7 +436,7 @@ int process_chk(struct task *t) //fprintf(stderr, "process_chk: 7\n"); /* FIXME: we allow up to for a connection to establish, but we should use another parameter */ - while (tv_ms_le2(&t->expire, &now)) + while (__tv_isle(&t->expire, &now)) tv_ms_add(&t->expire, &t->expire, s->inter); goto new_chk; } @@ -488,11 +487,11 @@ int process_chk(struct task *t) } s->curfd = -1; /* no check running anymore */ fd_delete(fd); - while (tv_ms_le2(&t->expire, &now)) + while (__tv_isle(&t->expire, &now)) tv_ms_add(&t->expire, &t->expire, s->inter); goto new_chk; } - else if (s->result < 0 || tv_ms_le2(&t->expire, &now)) { + else if (s->result < 0 || __tv_isle(&t->expire, &now)) { //fprintf(stderr, "process_chk: 10\n"); /* failure or timeout detected */ if (s->health > s->rise) { @@ -503,7 +502,7 @@ int process_chk(struct task *t) set_server_down(s); s->curfd = -1; fd_delete(fd); - while (tv_ms_le2(&t->expire, &now)) + while (__tv_isle(&t->expire, &now)) tv_ms_add(&t->expire, &t->expire, s->inter); goto new_chk; } @@ -512,12 +511,9 @@ int process_chk(struct task *t) //fprintf(stderr, "process_chk: 11\n"); s->result = 0; task_queue(t); /* restore t to its place in the task list */ - next_time = tv_ms_remain2(&now, &t->expire); + *next = t->expire; out: - /* Ensure that we don't report sub-millisecond timeouts */ - if (next_time != TIME_ETERNITY) - next_time++; - return next_time; + return; } diff --git a/src/client.c b/src/client.c index 4a891b06d1..52b281bded 100644 --- a/src/client.c +++ b/src/client.c @@ -1,7 +1,7 @@ /* * Client-side variables and functions. * - * Copyright 2000-2006 Willy Tarreau + * Copyright 2000-2007 Willy Tarreau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -386,7 +386,7 @@ int event_accept(int fd) { s->rep->rto = s->be->srvtimeout; s->rep->wto = s->fe->clitimeout; - s->rep->cto = 0; + tv_zero(&s->rep->cto); fd_insert(cfd); fdtab[cfd].owner = t; @@ -421,13 +421,13 @@ int event_accept(int fd) { tv_eternity(&s->rep->wex); tv_eternity(&t->expire); - if (s->fe->clitimeout) { + if (tv_isset(&s->fe->clitimeout)) { if (EV_FD_ISSET(cfd, DIR_RD)) { - tv_ms_add(&s->req->rex, &now, s->fe->clitimeout); + tv_add(&s->req->rex, &now, &s->fe->clitimeout); t->expire = s->req->rex; } if (EV_FD_ISSET(cfd, DIR_WR)) { - tv_ms_add(&s->rep->wex, &now, s->fe->clitimeout); + tv_add(&s->rep->wex, &now, &s->fe->clitimeout); t->expire = s->req->rex; } } diff --git a/src/ev_epoll.c b/src/ev_epoll.c index b4844998ad..a867e8dc36 100644 --- a/src/ev_epoll.c +++ b/src/ev_epoll.c @@ -220,16 +220,22 @@ REGPRM1 static void __fd_clo(int fd) /* * epoll() poller */ -REGPRM2 static void _do_poll(struct poller *p, int wait_time) +REGPRM2 static void _do_poll(struct poller *p, struct timeval *exp) { int status; int fd; int count; + int wait_time; if (likely(nbchanges)) fd_flush_changes(); /* now let's wait for events */ + if (tv_isset(exp)) + wait_time = tv_ms_remain(&now, exp); + else + wait_time = -1; + status = epoll_wait(epoll_fd, epoll_events, maxfd, wait_time); tv_now(&now); diff --git a/src/ev_poll.c b/src/ev_poll.c index c48f502151..3c97707cc8 100644 --- a/src/ev_poll.c +++ b/src/ev_poll.c @@ -81,10 +81,11 @@ REGPRM1 static void __fd_rem(const int fd) /* * Poll() poller */ -REGPRM2 static void _do_poll(struct poller *p, int wait_time) +REGPRM2 static void _do_poll(struct poller *p, struct timeval *exp) { int status; int fd, nbfd; + int wait_time; int fds, count; int sr, sw; @@ -123,6 +124,11 @@ REGPRM2 static void _do_poll(struct poller *p, int wait_time) } /* now let's wait for events */ + if (tv_isset(exp)) + wait_time = tv_ms_remain(&now, exp); + else + wait_time = -1; + status = poll(poll_events, nbfd, wait_time); tv_now(&now); diff --git a/src/ev_select.c b/src/ev_select.c index ed79abf01e..fb5cc41eab 100644 --- a/src/ev_select.c +++ b/src/ev_select.c @@ -78,7 +78,7 @@ REGPRM1 static void __fd_rem(int fd) /* * Select() poller */ -REGPRM2 static void _do_poll(struct poller *p, int wait_time) +REGPRM2 static void _do_poll(struct poller *p, struct timeval *exp) { int status; int fd, i; @@ -89,12 +89,14 @@ REGPRM2 static void _do_poll(struct poller *p, int wait_time) /* allow select to return immediately when needed */ delta.tv_sec = delta.tv_usec = 0; - if (wait_time > 0) { /* FIXME */ - /* Convert to timeval */ - /* to avoid eventual select loops due to timer precision */ - wait_time += SCHEDULER_RESOLUTION; - delta.tv_sec = wait_time / 1000; - delta.tv_usec = (wait_time % 1000) * 1000; + if (tv_isset(exp)) { + tv_remain(&now, exp, &delta); + /* To avoid eventual select loops due to timer precision */ + delta.tv_usec += SCHEDULER_RESOLUTION * 1000; + if (delta.tv_usec >= 1000000) { + delta.tv_usec -= 1000000; + delta.tv_sec ++; + } } /* let's restore fdset state */ @@ -118,7 +120,7 @@ REGPRM2 static void _do_poll(struct poller *p, int wait_time) readnotnull ? tmp_evts[DIR_RD] : NULL, writenotnull ? tmp_evts[DIR_WR] : NULL, NULL, - (wait_time >= 0) ? &delta : NULL); + tv_isset(exp) ? &delta : NULL); tv_now(&now); diff --git a/src/ev_sepoll.c b/src/ev_sepoll.c index c3b777647e..d2fcc7c7c2 100644 --- a/src/ev_sepoll.c +++ b/src/ev_sepoll.c @@ -259,13 +259,14 @@ static struct ev_to_epoll { /* * speculative epoll() poller */ -REGPRM2 static void _do_poll(struct poller *p, int wait_time) +REGPRM2 static void _do_poll(struct poller *p, struct timeval *exp) { static unsigned int last_skipped; int status; int fd, opcode; int count; int spec_idx; + int wait_time; /* Here we have two options : @@ -370,6 +371,12 @@ REGPRM2 static void _do_poll(struct poller *p, int wait_time) } wait_time = 0; } + else { + if (tv_isset(exp)) + wait_time = tv_ms_remain(&now, exp); + else + wait_time = -1; + } last_skipped = 0; /* now let's wait for events */ diff --git a/src/haproxy.c b/src/haproxy.c index a2e335e1ee..0acf75fb5d 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -684,17 +684,17 @@ static void tell_old_pids(int sig) */ void run_poll_loop() { - int next_time; - tv_now(&now); + struct timeval next; + tv_now(&now); while (1) { - next_time = process_runnable_tasks(); + process_runnable_tasks(&next); /* stop when there's no connection left and we don't allow them anymore */ if (!actconn && listeners == 0) break; - cur_poller.poll(&cur_poller, next_time); + cur_poller.poll(&cur_poller, &next); } } diff --git a/src/proto_http.c b/src/proto_http.c index 9506b167eb..0f78d07a74 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -442,8 +442,8 @@ void client_retnclose(struct session *s, const struct chunk *msg) EV_FD_CLR(s->cli_fd, DIR_RD); EV_FD_SET(s->cli_fd, DIR_WR); tv_eternity(&s->req->rex); - if (s->fe->clitimeout) - tv_ms_add(&s->rep->wex, &now, s->fe->clitimeout); + if (tv_isset(&s->fe->clitimeout)) + tv_add(&s->rep->wex, &now, &s->fe->clitimeout); else tv_eternity(&s->rep->wex); s->cli_state = CL_STSHUTR; @@ -532,7 +532,7 @@ static http_meth_t find_http_meth(const char *str, const int len) * the time the task accepts to wait, or TIME_ETERNITY for * infinity. */ -int process_session(struct task *t) +void process_session(struct task *t, struct timeval *next) { struct session *s = t->context; int fsm_resync = 0; @@ -563,11 +563,11 @@ int process_session(struct task *t) /* 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_ms_remain2(&now, &t->expire) <= 0) + if (tv_remain2(&now, &t->expire) <= 0) exit(100); #endif - - return tv_ms_remain2(&now, &t->expire); /* nothing more to do */ + *next = t->expire; + return; /* nothing more to do */ } s->fe->feconn--; @@ -615,7 +615,7 @@ int process_session(struct task *t) task_delete(t); session_free(s); task_free(t); - return TIME_ETERNITY; /* rest in peace for eternity */ + tv_eternity(next); } @@ -1529,7 +1529,7 @@ int process_cli(struct session *t) } /* 3: has the read timeout expired ? */ - else if (unlikely(tv_ms_le2(&req->rex, &now))) { + else if (unlikely(__tv_isle(&req->rex, &now))) { /* read timeout : give up with an error message. */ txn->status = 408; client_retnclose(t, error_message(t, HTTP_ERR_408)); @@ -1547,8 +1547,8 @@ int process_cli(struct session *t) * full. We cannot loop here since stream_sock_read will disable it only if * req->l == rlim-data */ - if (t->fe->clitimeout) - tv_ms_add(&req->rex, &now, t->fe->clitimeout); + if (tv_isset(&t->fe->clitimeout)) + tv_add(&req->rex, &now, &t->fe->clitimeout); else tv_eternity(&req->rex); } @@ -1912,8 +1912,8 @@ int process_cli(struct session *t) t->logs.t_request = tv_ms_elapsed(&t->logs.tv_accept, &now); - if (!t->fe->clitimeout || - (t->srv_state < SV_STDATA && t->be->srvtimeout)) { + if (!tv_isset(&t->fe->clitimeout) || + (t->srv_state < SV_STDATA && tv_isset(&t->be->srvtimeout))) { /* If the client has no timeout, or if the server is not ready yet, * and we know for sure that it can expire, then it's cleaner to * disable the timeout on the client side so that too low values @@ -1936,8 +1936,10 @@ int process_cli(struct session *t) /* flush the request so that we can drop the connection early * if the client closes first. */ - tv_ms_add(&req->cex, &now, - t->be->contimeout ? t->be->contimeout : 0); + if (tv_isset(&t->be->contimeout)) + tv_add(&req->cex, &now, &t->be->contimeout); + else + req->cex = now; } /* OK let's go on with the BODY now */ @@ -1996,14 +1998,14 @@ int process_cli(struct session *t) /* We must ensure that the read part is still alive when switching * to shutw */ EV_FD_SET(t->cli_fd, DIR_RD); - if (t->fe->clitimeout) - tv_ms_add(&req->rex, &now, t->fe->clitimeout); + if (tv_isset(&t->fe->clitimeout)) + tv_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_ms_le2(&req->rex, &now)) { + else if (__tv_isle(&req->rex, &now)) { EV_FD_CLR(t->cli_fd, DIR_RD); tv_eternity(&req->rex); t->cli_state = CL_STSHUTR; @@ -2020,15 +2022,15 @@ int process_cli(struct session *t) return 1; } /* write timeout */ - else if (tv_ms_le2(&rep->wex, &now)) { + else if (__tv_isle(&rep->wex, &now)) { EV_FD_CLR(t->cli_fd, DIR_WR); tv_eternity(&rep->wex); shutdown(t->cli_fd, SHUT_WR); /* We must ensure that the read part is still alive when switching * to shutw */ EV_FD_SET(t->cli_fd, DIR_RD); - if (t->fe->clitimeout) - tv_ms_add(&req->rex, &now, t->fe->clitimeout); + if (tv_isset(&t->fe->clitimeout)) + tv_add(&req->rex, &now, &t->fe->clitimeout); t->cli_state = CL_STSHUTW; if (!(t->flags & SN_ERR_MASK)) @@ -2053,8 +2055,8 @@ int process_cli(struct session *t) } else { /* there's still some space in the buffer */ if (EV_FD_COND_S(t->cli_fd, DIR_RD)) { - if (!t->fe->clitimeout || - (t->srv_state < SV_STDATA && t->be->srvtimeout)) + if (!tv_isset(&t->fe->clitimeout) || + (t->srv_state < SV_STDATA && tv_isset(&t->be->srvtimeout))) /* If the client has no timeout, or if the server not ready yet, and we * know for sure that it can expire, then it's cleaner to disable the * timeout on the client side so that too low values cannot make the @@ -2062,7 +2064,7 @@ int process_cli(struct session *t) */ tv_eternity(&req->rex); else - tv_ms_add(&req->rex, &now, t->fe->clitimeout); + tv_add(&req->rex, &now, &t->fe->clitimeout); } } @@ -2076,8 +2078,8 @@ int process_cli(struct session *t) /* buffer not empty */ if (EV_FD_COND_S(t->cli_fd, DIR_WR)) { /* restart writing */ - if (t->fe->clitimeout) { - tv_ms_add(&rep->wex, &now, t->fe->clitimeout); + if (tv_isset(&t->fe->clitimeout)) { + tv_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; @@ -2112,7 +2114,7 @@ int process_cli(struct session *t) t->cli_state = CL_STCLOSE; return 1; } - else if (tv_ms_le2(&rep->wex, &now)) { + else if (__tv_isle(&rep->wex, &now)) { tv_eternity(&rep->wex); fd_delete(t->cli_fd); t->cli_state = CL_STCLOSE; @@ -2149,8 +2151,8 @@ int process_cli(struct session *t) /* buffer not empty */ if (EV_FD_COND_S(t->cli_fd, DIR_WR)) { /* restart writing */ - if (t->fe->clitimeout) { - tv_ms_add(&rep->wex, &now, t->fe->clitimeout); + if (tv_isset(&t->fe->clitimeout)) { + tv_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; @@ -2184,7 +2186,7 @@ int process_cli(struct session *t) t->cli_state = CL_STCLOSE; return 1; } - else if (tv_ms_le2(&req->rex, &now)) { + else if (__tv_isle(&req->rex, &now)) { tv_eternity(&req->rex); fd_delete(t->cli_fd); t->cli_state = CL_STCLOSE; @@ -2215,8 +2217,8 @@ int process_cli(struct session *t) } else { /* there's still some space in the buffer */ if (EV_FD_COND_S(t->cli_fd, DIR_RD)) { - if (t->fe->clitimeout) - tv_ms_add(&req->rex, &now, t->fe->clitimeout); + if (tv_isset(&t->fe->clitimeout)) + tv_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); @@ -2281,7 +2283,7 @@ int process_srv(struct session *t) * already set the connect expiration date to the right * timeout. We just have to check that it has not expired. */ - if (!tv_ms_le2(&req->cex, &now)) + if (!__tv_isle(&req->cex, &now)) return 0; /* We will set the queue timer to the time spent, just for @@ -2303,7 +2305,7 @@ int process_srv(struct session *t) * to any other session to release it and wake us up again. */ if (t->pend_pos) { - if (!tv_ms_le2(&req->cex, &now)) + if (!__tv_isle(&req->cex, &now)) return 0; else { /* we've been waiting too long here */ @@ -2349,7 +2351,7 @@ int process_srv(struct session *t) srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL); return 1; } - if (!(req->flags & BF_WRITE_STATUS) && !tv_ms_le2(&req->cex, &now)) { + if (!(req->flags & BF_WRITE_STATUS) && !__tv_isle(&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 */ } @@ -2416,8 +2418,8 @@ int process_srv(struct session *t) tv_eternity(&req->wex); } else /* need the right to write */ { EV_FD_SET(t->srv_fd, DIR_WR); - if (t->be->srvtimeout) { - tv_ms_add(&req->wex, &now, t->be->srvtimeout); + if (tv_isset(&t->be->srvtimeout)) { + tv_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; @@ -2428,8 +2430,8 @@ int process_srv(struct session *t) 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_ms_add(&rep->rex, &now, t->be->srvtimeout); + if (tv_isset(&t->be->srvtimeout)) + tv_add(&rep->rex, &now, &t->be->srvtimeout); else tv_eternity(&rep->rex); @@ -2517,8 +2519,8 @@ int process_srv(struct session *t) * full. We cannot loop here since stream_sock_read will disable it only if * rep->l == rlim-data */ - if (t->be->srvtimeout) - tv_ms_add(&rep->rex, &now, t->be->srvtimeout); + if (tv_isset(&t->be->srvtimeout)) + tv_add(&rep->rex, &now, &t->be->srvtimeout); else tv_eternity(&rep->rex); } @@ -2584,7 +2586,7 @@ int process_srv(struct session *t) /* read timeout : return a 504 to the client. */ else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_RD) && - tv_ms_le2(&rep->rex, &now))) { + __tv_isle(&rep->rex, &now))) { tv_eternity(&rep->rex); tv_eternity(&req->wex); fd_delete(t->srv_fd); @@ -2624,8 +2626,8 @@ int process_srv(struct session *t) /* We must ensure that the read part is still * alive when switching to shutw */ EV_FD_SET(t->srv_fd, DIR_RD); - if (t->be->srvtimeout) - tv_ms_add(&rep->rex, &now, t->be->srvtimeout); + if (tv_isset(&t->be->srvtimeout)) + tv_add(&rep->rex, &now, &t->be->srvtimeout); shutdown(t->srv_fd, SHUT_WR); t->srv_state = SV_STSHUTW; @@ -2638,15 +2640,15 @@ int process_srv(struct session *t) * some work to do on the headers. */ else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_WR) && - tv_ms_le2(&req->wex, &now))) { + __tv_isle(&req->wex, &now))) { EV_FD_CLR(t->srv_fd, DIR_WR); tv_eternity(&req->wex); shutdown(t->srv_fd, SHUT_WR); /* We must ensure that the read part is still alive * when switching to shutw */ EV_FD_SET(t->srv_fd, DIR_RD); - if (t->be->srvtimeout) - tv_ms_add(&rep->rex, &now, t->be->srvtimeout); + if (tv_isset(&t->be->srvtimeout)) + tv_add(&rep->rex, &now, &t->be->srvtimeout); t->srv_state = SV_STSHUTW; if (!(t->flags & SN_ERR_MASK)) @@ -2667,8 +2669,8 @@ int process_srv(struct session *t) else if (likely(req->l)) { if (EV_FD_COND_S(t->srv_fd, DIR_WR)) { /* restart writing */ - if (t->be->srvtimeout) { - tv_ms_add(&req->wex, &now, t->be->srvtimeout); + if (tv_isset(&t->be->srvtimeout)) { + tv_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; @@ -2964,8 +2966,8 @@ int process_srv(struct session *t) /* We must ensure that the read part is still alive when switching * to shutw */ EV_FD_SET(t->srv_fd, DIR_RD); - if (t->be->srvtimeout) - tv_ms_add(&rep->rex, &now, t->be->srvtimeout); + if (tv_isset(&t->be->srvtimeout)) + tv_add(&rep->rex, &now, &t->be->srvtimeout); shutdown(t->srv_fd, SHUT_WR); t->srv_state = SV_STSHUTW; @@ -3034,14 +3036,14 @@ int process_srv(struct session *t) /* We must ensure that the read part is still alive when switching * to shutw */ EV_FD_SET(t->srv_fd, DIR_RD); - if (t->be->srvtimeout) - tv_ms_add(&rep->rex, &now, t->be->srvtimeout); + if (tv_isset(&t->be->srvtimeout)) + tv_add(&rep->rex, &now, &t->be->srvtimeout); t->srv_state = SV_STSHUTW; return 1; } /* read timeout */ - else if (tv_ms_le2(&rep->rex, &now)) { + else if (__tv_isle(&rep->rex, &now)) { EV_FD_CLR(t->srv_fd, DIR_RD); tv_eternity(&rep->rex); t->srv_state = SV_STSHUTR; @@ -3052,15 +3054,15 @@ int process_srv(struct session *t) return 1; } /* write timeout */ - else if (tv_ms_le2(&req->wex, &now)) { + else if (__tv_isle(&req->wex, &now)) { EV_FD_CLR(t->srv_fd, DIR_WR); tv_eternity(&req->wex); shutdown(t->srv_fd, SHUT_WR); /* We must ensure that the read part is still alive when switching * to shutw */ EV_FD_SET(t->srv_fd, DIR_RD); - if (t->be->srvtimeout) - tv_ms_add(&rep->rex, &now, t->be->srvtimeout); + if (tv_isset(&t->be->srvtimeout)) + tv_add(&rep->rex, &now, &t->be->srvtimeout); t->srv_state = SV_STSHUTW; if (!(t->flags & SN_ERR_MASK)) t->flags |= SN_ERR_SRVTO; @@ -3079,8 +3081,8 @@ int process_srv(struct session *t) else { /* buffer not empty, there are still data to be transferred */ if (EV_FD_COND_S(t->srv_fd, DIR_WR)) { /* restart writing */ - if (t->be->srvtimeout) { - tv_ms_add(&req->wex, &now, t->be->srvtimeout); + if (tv_isset(&t->be->srvtimeout)) { + tv_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; @@ -3098,8 +3100,8 @@ int process_srv(struct session *t) } else { if (EV_FD_COND_S(t->srv_fd, DIR_RD)) { - if (t->be->srvtimeout) - tv_ms_add(&rep->rex, &now, t->be->srvtimeout); + if (tv_isset(&t->be->srvtimeout)) + tv_add(&rep->rex, &now, &t->be->srvtimeout); else tv_eternity(&rep->rex); } @@ -3147,7 +3149,7 @@ int process_srv(struct session *t) return 1; } - else if (tv_ms_le2(&req->wex, &now)) { + else if (__tv_isle(&req->wex, &now)) { //EV_FD_CLR(t->srv_fd, DIR_WR); tv_eternity(&req->wex); fd_delete(t->srv_fd); @@ -3176,8 +3178,8 @@ int process_srv(struct session *t) else { /* buffer not empty */ if (EV_FD_COND_S(t->srv_fd, DIR_WR)) { /* restart writing */ - if (t->be->srvtimeout) { - tv_ms_add(&req->wex, &now, t->be->srvtimeout); + if (tv_isset(&t->be->srvtimeout)) { + tv_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; @@ -3228,7 +3230,7 @@ int process_srv(struct session *t) return 1; } - else if (tv_ms_le2(&rep->rex, &now)) { + else if (__tv_isle(&rep->rex, &now)) { //EV_FD_CLR(t->srv_fd, DIR_RD); tv_eternity(&rep->rex); fd_delete(t->srv_fd); @@ -3255,8 +3257,8 @@ int process_srv(struct session *t) } else { if (EV_FD_COND_S(t->srv_fd, DIR_RD)) { - if (t->be->srvtimeout) - tv_ms_add(&rep->rex, &now, t->be->srvtimeout); + if (tv_isset(&t->be->srvtimeout)) + tv_add(&rep->rex, &now, &t->be->srvtimeout); else tv_eternity(&rep->rex); } @@ -4375,7 +4377,7 @@ void manage_client_side_cookies(struct session *t, struct buffer *req) }/* end while(srv) */ }/* end else if server == NULL */ - tv_ms_add(&asession_temp->expire, &now, t->be->appsession_timeout); + tv_add(&asession_temp->expire, &now, &t->be->appsession_timeout); }/* end if ((t->proxy->appsession_name != NULL) ... */ } @@ -4835,7 +4837,7 @@ void manage_server_side_cookies(struct session *t, struct buffer *rtr) if (asession_temp->serverid[0] == '\0') memcpy(asession_temp->serverid, t->srv->id, server_id_len); - tv_ms_add(&asession_temp->expire, &now, t->be->appsession_timeout); + tv_add(&asession_temp->expire, &now, &t->be->appsession_timeout); #if defined(DEBUG_HASH) print_table(&(t->be->htbl_proxy)); @@ -4997,7 +4999,7 @@ void get_srv_from_appsession(struct session *t, const char *begin, int len) pool_free_to(apools.sessid, local_asession.sessid); } - tv_ms_add(&asession_temp->expire, &now, t->be->appsession_timeout); + tv_add(&asession_temp->expire, &now, &t->be->appsession_timeout); asession_temp->request_count++; #if defined(DEBUG_HASH) diff --git a/src/proxy.c b/src/proxy.c index 3cc355a84b..dd7f993e34 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -1,7 +1,7 @@ /* * Proxy variables and functions. * - * Copyright 2000-2006 Willy Tarreau + * Copyright 2000-2007 Willy Tarreau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -170,17 +170,16 @@ int start_proxies(int verbose) /* * this function enables proxies when there are enough free sessions, * or stops them when the table is full. It is designed to be called from the - * select_loop(). It returns the time left before next expiration event - * during stop time, TIME_ETERNITY otherwise. + * select_loop(). It returns the date of next expiration event during stop + * time, ETERNITY otherwise. */ -int maintain_proxies(void) +void maintain_proxies(struct timeval *next) { struct proxy *p; struct listener *l; - int tleft; /* time left */ p = proxy; - tleft = TIME_ETERNITY; /* infinite time */ + tv_eternity(next); /* if there are enough free sessions, we'll activate proxies */ if (actconn < global.maxconn) { @@ -233,13 +232,13 @@ int maintain_proxies(void) p->state = PR_STSTOPPED; } else { - tleft = MINTIME(t, tleft); + tv_bound(next, &p->stop_time); } } p = p->next; } } - return tleft; + return; } diff --git a/src/queue.c b/src/queue.c index 9b53687de1..37d3ed8507 100644 --- a/src/queue.c +++ b/src/queue.c @@ -45,9 +45,9 @@ unsigned int srv_dynamic_maxconn(const struct server *s) /* * Manages a server's connection queue. If woken up, will try to dequeue as * many pending sessions as possible, and wake them up. The task has nothing - * else to do, so it always returns TIME_ETERNITY. + * else to do, so it always returns ETERNITY. */ -int process_srv_queue(struct task *t) +void process_srv_queue(struct task *t, struct timeval *next) { struct server *s = (struct server*)t->context; struct proxy *p = s->proxy; @@ -65,7 +65,7 @@ int process_srv_queue(struct task *t) task_wakeup(sess->task); } - return TIME_ETERNITY; + tv_eternity(next); } /* Detaches the next pending connection from either a server or a proxy, and diff --git a/src/stream_sock.c b/src/stream_sock.c index e420ace348..4691a9c5a4 100644 --- a/src/stream_sock.c +++ b/src/stream_sock.c @@ -165,8 +165,8 @@ int stream_sock_read(int fd) { */ if (b->flags & BF_PARTIAL_READ) { - if (b->rto) { - tv_ms_add(&b->rex, &now, b->rto); + if (tv_isset(&b->rto)) { + tv_add(&b->rex, &now, &b->rto); goto out_wakeup; } out_eternity: @@ -315,8 +315,8 @@ int stream_sock_write(int fd) { */ if (b->flags & BF_PARTIAL_WRITE) { - if (b->wto) { - tv_ms_add(&b->wex, &now, b->wto); + if (tv_isset(&b->wto)) { + tv_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 diff --git a/src/task.c b/src/task.c index 8905581284..953da6c7c5 100644 --- a/src/task.c +++ b/src/task.c @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -23,9 +24,6 @@ #include -/* FIXME : this should be removed very quickly ! */ -extern int maintain_proxies(void); - void **pool_task= NULL; void **pool_tree64 = NULL; static struct ultree *stack[LLONGBITS]; @@ -47,6 +45,7 @@ struct task *_task_wakeup(struct task *t) { return __task_wakeup(t); } + /* * task_queue() * @@ -80,19 +79,15 @@ struct task *task_queue(struct task *task) /* * Extract all expired timers from the wait queue, and wakes up all - * associated tasks. - * Returns the time to wait for next task (next_time). - * - * FIXME: Use an alternative queue for ETERNITY tasks. + * associated tasks. Returns the date of next event (or eternity). * */ -int wake_expired_tasks() +void wake_expired_tasks(struct timeval *next) { __label__ out; int slen; struct task *task; void *data; - int next_time; /* * Hint: tasks are *rarely* expired. So we can try to optimize @@ -102,19 +97,19 @@ int wake_expired_tasks() if (likely(timer_wq.data != NULL)) { task = LIST_ELEM(timer_wq.data, struct task *, qlist); if (likely(__tv_isge(&task->expire, &now) > 0)) { - next_time = tv_ms_remain(&now, &task->expire); + __tv_remain(&now, &task->expire, next); goto out; } } /* OK we lose. Let's scan the tree then. */ - next_time = TIME_ETERNITY; + tv_eternity(next); tree64_foreach(&timer_wq, data, stack, slen) { task = LIST_ELEM(data, struct task *, qlist); if (__tv_isgt(&task->expire, &now)) { - next_time = tv_ms_remain(&now, &task->expire); + __tv_remain2(&now, &task->expire, next); break; } @@ -131,10 +126,7 @@ int wake_expired_tasks() } } out: - /* Ensure that we don't report sub-millisecond timeouts */ - if (next_time != TIME_ETERNITY) - next_time++; - return next_time; + return; } /* @@ -142,17 +134,16 @@ int wake_expired_tasks() * - wake up all expired tasks * - call all runnable tasks * - call maintain_proxies() to enable/disable the listeners - * - return the delay till next event in ms, -1 = wait indefinitely + * - return the date of next event in or eternity. * */ -int process_runnable_tasks() +void process_runnable_tasks(struct timeval *next) { - int next_time; - int time2; + struct timeval temp; struct task *t; void *queue; - next_time = wake_expired_tasks(); + wake_expired_tasks(next); /* process each task in the run queue now. Each task may be deleted * since we only use the run queue's head. Note that any task can be * woken up by any other task and it will be processed immediately @@ -161,21 +152,20 @@ int process_runnable_tasks() queue = run_queue; foreach_dlist_item(t, queue, struct task *, qlist) { - int temp_time; - DLIST_DEL(&t->qlist); t->qlist.p = NULL; t->state = TASK_IDLE; - temp_time = t->process(t); - next_time = MINTIME(temp_time, next_time); + t->process(t, &temp); + tv_bound(next, &temp); } /* maintain all proxies in a consistent state. This should quickly * become a task because it becomes expensive when there are huge * numbers of proxies. */ - time2 = maintain_proxies(); - return MINTIME(time2, next_time); + maintain_proxies(&temp); + tv_bound(next, &temp); + return; } /* diff --git a/src/time.c b/src/time.c index 262bc44911..cf3d5cff69 100644 --- a/src/time.c +++ b/src/time.c @@ -94,6 +94,33 @@ REGPRM2 unsigned long _tv_ms_elapsed(const struct timeval *tv1, const struct tim return __tv_ms_elapsed(tv1, tv2); } +/* + * adds to , set the result to and returns a pointer + */ +REGPRM3 struct timeval *_tv_add(struct timeval *tv, const struct timeval *from, const struct timeval *inc) +{ + return __tv_add(tv, from, inc); +} + +/* + * Computes the remaining time between tv1=now and event=tv2. if tv2 is passed, + * 0 is returned. The result is stored into tv. + */ +REGPRM3 struct timeval *_tv_remain(const struct timeval *tv1, const struct timeval *tv2, struct timeval *tv) +{ + return __tv_remain(tv1, tv2, tv); +} + +/* + * Computes the remaining time between tv1=now and event=tv2. if tv2 is passed, + * 0 is returned. The result is stored into tv. Returns ETERNITY if tv2 is + * eternity. + */ +REGPRM3 struct timeval *_tv_remain2(const struct timeval *tv1, const struct timeval *tv2, struct timeval *tv) +{ + return __tv_remain2(tv1, tv2, tv); +} + /* * Local variables: * c-indent-level: 8