[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.
This commit is contained in:
Willy Tarreau 2007-05-12 22:35:00 +02:00
parent 49fa3a1453
commit d825eef9c5
26 changed files with 225 additions and 190 deletions

View File

@ -44,7 +44,7 @@ void destroy(void *data);
static void print_table(const CHTbl *htbl); static void print_table(const CHTbl *htbl);
#endif #endif
int appsession_refresh(struct task *t); void appsession_refresh(struct task *t, struct timeval *next);
int appsession_task_init(void); int appsession_task_init(void);
int appsession_init(void); int appsession_init(void);
void appsession_cleanup(void); void appsession_cleanup(void);

View File

@ -2,7 +2,7 @@
include/proto/checks.h include/proto/checks.h
Functions prototypes for the checks. 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 This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -25,7 +25,7 @@
#include <types/task.h> #include <types/task.h>
#include <common/config.h> #include <common/config.h>
int process_chk(struct task *t); void process_chk(struct task *t, struct timeval *next);
#endif /* _PROTO_CHECKS_H */ #endif /* _PROTO_CHECKS_H */

View File

@ -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)]) #define HTTP_IS_VER_TOKEN(x) (http_is_ver_token[(unsigned char)(x)])
int event_accept(int fd); 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_cli(struct session *t);
int process_srv(struct session *t); int process_srv(struct session *t);

View File

@ -2,7 +2,7 @@
include/proto/proxy.h include/proto/proxy.h
This file defines function prototypes for proxy management. 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 This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -23,10 +23,11 @@
#define _PROTO_PROXY_H #define _PROTO_PROXY_H
#include <common/config.h> #include <common/config.h>
#include <common/time.h>
#include <types/proxy.h> #include <types/proxy.h>
int start_proxies(int verbose); int start_proxies(int verbose);
int maintain_proxies(void); void maintain_proxies(struct timeval *next);
void soft_stop(void); void soft_stop(void);
void pause_proxy(struct proxy *p); void pause_proxy(struct proxy *p);
void pause_proxies(void); void pause_proxies(void);

View File

@ -2,7 +2,7 @@
include/proto/queue.h include/proto/queue.h
This file defines everything related to queues. 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 This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public 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 session *pendconn_get_next_sess(struct server *srv, struct proxy *px);
struct pendconn *pendconn_add(struct session *sess); struct pendconn *pendconn_add(struct session *sess);
void pendconn_free(struct pendconn *p); 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); unsigned int srv_dynamic_maxconn(const struct server *s);

View File

@ -111,12 +111,10 @@ struct task *task_queue(struct task *task);
* - wake up all expired tasks * - wake up all expired tasks
* - call all runnable tasks * - call all runnable tasks
* - call maintain_proxies() to enable/disable the listeners * - 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 <next> or eternity.
* Note: this part should be rewritten with the O(ln(n)) scheduler.
*
*/ */
int process_runnable_tasks(); void process_runnable_tasks(struct timeval *next);
#endif /* _PROTO_TASK_H */ #endif /* _PROTO_TASK_H */

View File

@ -63,9 +63,9 @@ struct buffer {
struct timeval rex; /* expiration date for a read */ struct timeval rex; /* expiration date for a read */
struct timeval wex; /* expiration date for a write */ struct timeval wex; /* expiration date for a write */
struct timeval cex; /* expiration date for a connect */ struct timeval cex; /* expiration date for a connect */
int rto; /* read timeout */ struct timeval rto; /* read timeout */
int wto; /* write timeout */ struct timeval wto; /* write timeout */
int cto; /* connect timeout */ struct timeval cto; /* connect timeout */
unsigned int l; /* data length */ unsigned int l; /* data length */
char *r, *w, *lr; /* read ptr, write ptr, last read */ char *r, *w, *lr; /* read ptr, write ptr, last read */
char *rlim; /* read limit, used for header rewriting */ char *rlim; /* read limit, used for header rewriting */

View File

@ -81,7 +81,7 @@ struct fdtab {
* it returns 0. It may be the same as clr(). * 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 * - clo() should be used to do indicate the poller that fd will be closed. It
* may be the same as rem() on some pollers. * 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 <exp>
*/ */
struct poller { struct poller {
void *private; /* any private data for the 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 <fd> for <dir> if set */ int REGPRM2 (*cond_c)(const int fd, int dir); /* clear polling on <fd> for <dir> if set */
void REGPRM1 (*rem)(const int fd); /* remove any polling on <fd> */ void REGPRM1 (*rem)(const int fd); /* remove any polling on <fd> */
void REGPRM1 (*clo)(const int fd); /* mark <fd> as closed */ void REGPRM1 (*clo)(const int fd); /* mark <fd> 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 */ int REGPRM1 (*init)(struct poller *p); /* poller initialization */
void REGPRM1 (*term)(struct poller *p); /* termination of this poller */ void REGPRM1 (*term)(struct poller *p); /* termination of this poller */
int REGPRM1 (*test)(struct poller *p); /* pre-init check of the poller */ int REGPRM1 (*test)(struct poller *p); /* pre-init check of the poller */

View File

@ -96,7 +96,6 @@ struct proxy {
char *appsession_name; /* name of the cookie to look for */ char *appsession_name; /* name of the cookie to look for */
int appsession_name_len; /* strlen(appsession_name), computed only once */ int appsession_name_len; /* strlen(appsession_name), computed only once */
int appsession_len; /* length of the appsession cookie value to be used */ int appsession_len; /* length of the appsession cookie value to be used */
int appsession_timeout;
CHTbl htbl_proxy; /* Per Proxy hashtable */ CHTbl htbl_proxy; /* Per Proxy hashtable */
char *capture_name; /* beginning of the name of the cookie to capture */ char *capture_name; /* beginning of the name of the cookie to capture */
int capture_namelen; /* length of the cookie name to match */ 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 */ 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 */ 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 monitor_uri_len; /* length of the string above. 0 if unused */
int clitimeout; /* client I/O timeout (in milliseconds) */ struct timeval clitimeout; /* client I/O timeout (in milliseconds) */
int srvtimeout; /* server I/O timeout (in milliseconds) */ struct timeval srvtimeout; /* server I/O timeout (in milliseconds) */
int contimeout; /* connect timeout (in milliseconds) */ struct timeval contimeout; /* connect timeout (in milliseconds) */
struct timeval appsession_timeout;
char *id; /* proxy id */ char *id; /* proxy id */
struct list pendconns; /* pending connections with no server assigned yet */ struct list pendconns; /* pending connections with no server assigned yet */
int nbpend, nbpend_max; /* number of pending connections with no server assigned yet */ int nbpend, nbpend_max; /* number of pending connections with no server assigned yet */

View File

@ -2,7 +2,7 @@
include/types/task.h include/types/task.h
Macros, variables and structures for task management. 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 This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public 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 */ struct ultree *wq; /* NULL if unqueued, or back ref to the carrier node in the WQ */
int state; /* task state : IDLE or RUNNING */ int state; /* task state : IDLE or RUNNING */
struct timeval expire; /* next expiration time for this task, use only for fast sorting */ 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 */ void *context; /* the task's context */
}; };

View File

@ -125,7 +125,7 @@ int appsession_task_init(void)
return 0; return 0;
} }
int appsession_refresh(struct task *t) void appsession_refresh(struct task *t, struct timeval *next)
{ {
struct proxy *p = proxy; struct proxy *p = proxy;
CHTbl *htbl; CHTbl *htbl;
@ -143,7 +143,7 @@ int appsession_refresh(struct task *t)
for (element = list_head(&htbl->table[i]); for (element = list_head(&htbl->table[i]);
element != NULL; element = list_next(element)) { element != NULL; element = list_next(element)) {
asession = (appsess *)list_data(element); asession = (appsess *)list_data(element);
if (tv_ms_le2(&asession->expire, &now)) { if (__tv_isle(&asession->expire, &now)) {
if ((global.mode & MODE_DEBUG) && if ((global.mode & MODE_DEBUG) &&
(!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) { (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
int len; int len;
@ -165,7 +165,7 @@ int appsession_refresh(struct task *t)
} }
else else
element = last; element = last;
}/* end if (tv_ms_le2(&asession->expire, &now)) */ }/* end if (__tv_isle(&asession->expire, &now)) */
else else
last = element; last = element;
}/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(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; p = p->next;
} }
tv_ms_add(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */ tv_ms_add(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
return TBLCHKINT; *next = t->expire;
} /* end appsession_refresh */ } /* end appsession_refresh */
int match_str(const void *key1, const void *key2) int match_str(const void *key1, const void *key2)

View File

@ -1,7 +1,7 @@
/* /*
* Backend variables and functions. * Backend variables and 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * 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; s->srv->cur_sess_max = s->srv->cur_sess;
} }
if (s->be->contimeout) if (tv_isset(&s->be->contimeout))
tv_ms_add(&s->req->cex, &now, s->be->contimeout); tv_add(&s->req->cex, &now, &s->be->contimeout);
else else
tv_eternity(&s->req->cex); tv_eternity(&s->req->cex);
return SN_ERR_NONE; /* connection is OK */ return SN_ERR_NONE; /* connection is OK */
@ -680,8 +680,8 @@ int srv_redispatch_connect(struct session *t)
case SRV_STATUS_QUEUED: case SRV_STATUS_QUEUED:
/* FIXME-20060503 : we should use the queue timeout instead */ /* FIXME-20060503 : we should use the queue timeout instead */
if (t->be->contimeout) if (tv_isset(&t->be->contimeout))
tv_ms_add(&t->req->cex, &now, t->be->contimeout); tv_add(&t->req->cex, &now, &t->be->contimeout);
else else
tv_eternity(&t->req->cex); tv_eternity(&t->req->cex);
t->srv_state = SV_STIDLE; t->srv_state = SV_STIDLE;

View File

@ -766,7 +766,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args)
curproxy->appsession_name = strdup(args[1]); curproxy->appsession_name = strdup(args[1]);
curproxy->appsession_name_len = strlen(curproxy->appsession_name); curproxy->appsession_name_len = strlen(curproxy->appsession_name);
curproxy->appsession_len = atoi(args[3]); 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); rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
if (rc) { if (rc) {
Alert("Error Init Appsession Hashtable.\n"); 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 */ 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]); Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
return 0; return 0;
} }
@ -869,10 +869,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args)
file, linenum, args[0]); file, linenum, args[0]);
return -1; return -1;
} }
curproxy->contimeout = atol(args[1]); __tv_from_ms(&curproxy->contimeout, atol(args[1]));
} }
else if (!strcmp(args[0], "clitimeout")) { /* client timeout */ 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", Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
file, linenum, args[0]); file, linenum, args[0]);
return 0; return 0;
@ -885,10 +885,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args)
file, linenum, args[0]); file, linenum, args[0]);
return -1; return -1;
} }
curproxy->clitimeout = atol(args[1]); __tv_from_ms(&curproxy->clitimeout, atol(args[1]));
} }
else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */ 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]); Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
return 0; return 0;
} }
@ -900,7 +900,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args)
file, linenum, args[0]); file, linenum, args[0]);
return -1; return -1;
} }
curproxy->srvtimeout = atol(args[1]); __tv_from_ms(&curproxy->srvtimeout, atol(args[1]));
} }
else if (!strcmp(args[0], "retries")) { /* connection retries */ else if (!strcmp(args[0], "retries")) { /* connection retries */
if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) 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) && if ((curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HTTP) &&
(((curproxy->cap & PR_CAP_FE) && !curproxy->clitimeout) || (((curproxy->cap & PR_CAP_FE) && !tv_isset(&curproxy->clitimeout)) ||
((curproxy->cap & PR_CAP_BE) && (curproxy->srv) && (!curproxy->contimeout || !curproxy->srvtimeout)))) { ((curproxy->cap & PR_CAP_BE) && (curproxy->srv) &&
(!tv_isset(&curproxy->contimeout) || !tv_isset(&curproxy->srvtimeout))))) {
Warning("parsing %s : missing timeouts for %s '%s'.\n" Warning("parsing %s : missing timeouts for %s '%s'.\n"
" | While not properly invalid, you will certainly encounter various problems\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" " | with such a configuration. To fix this, please ensure that all following\n"

View File

@ -1,7 +1,7 @@
/* /*
* Health-checks functions. * Health-checks 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * 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 * manages a server health-check. Returns
* the time the task accepts to wait, or TIME_ETERNITY for infinity. * 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; __label__ new_chk, out;
struct server *s = t->context; struct server *s = t->context;
struct sockaddr_in sa; struct sockaddr_in sa;
int fd; int fd;
int next_time;
//fprintf(stderr, "process_chk: task=%p\n", t); //fprintf(stderr, "process_chk: task=%p\n", t);
@ -289,9 +288,9 @@ int process_chk(struct task *t)
fd = s->curfd; fd = s->curfd;
if (fd < 0) { /* no check currently running */ if (fd < 0) { /* no check currently running */
//fprintf(stderr, "process_chk: 2\n"); //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 */ 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; goto out;
} }
@ -299,10 +298,10 @@ int process_chk(struct task *t)
* the server should not be checked. * the server should not be checked.
*/ */
if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) { 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); tv_ms_add(&t->expire, &t->expire, s->inter);
task_queue(t); /* restore t to its place in the task list */ 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; goto out;
} }
@ -410,7 +409,7 @@ int process_chk(struct task *t)
/* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */ /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
tv_ms_add(&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 */ 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) { else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
s->result = -1; /* a real error */ s->result = -1; /* a real error */
@ -422,7 +421,7 @@ int process_chk(struct task *t)
if (!s->result) { /* nothing done */ if (!s->result) { /* nothing done */
//fprintf(stderr, "process_chk: 6\n"); //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); tv_ms_add(&t->expire, &t->expire, s->inter);
goto new_chk; /* may be we should initialize a new check */ 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"); //fprintf(stderr, "process_chk: 7\n");
/* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */ /* FIXME: we allow up to <inter> 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); tv_ms_add(&t->expire, &t->expire, s->inter);
goto new_chk; goto new_chk;
} }
@ -488,11 +487,11 @@ int process_chk(struct task *t)
} }
s->curfd = -1; /* no check running anymore */ s->curfd = -1; /* no check running anymore */
fd_delete(fd); 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); tv_ms_add(&t->expire, &t->expire, s->inter);
goto new_chk; 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"); //fprintf(stderr, "process_chk: 10\n");
/* failure or timeout detected */ /* failure or timeout detected */
if (s->health > s->rise) { if (s->health > s->rise) {
@ -503,7 +502,7 @@ int process_chk(struct task *t)
set_server_down(s); set_server_down(s);
s->curfd = -1; s->curfd = -1;
fd_delete(fd); 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); tv_ms_add(&t->expire, &t->expire, s->inter);
goto new_chk; goto new_chk;
} }
@ -512,12 +511,9 @@ int process_chk(struct task *t)
//fprintf(stderr, "process_chk: 11\n"); //fprintf(stderr, "process_chk: 11\n");
s->result = 0; s->result = 0;
task_queue(t); /* restore t to its place in the task list */ task_queue(t); /* restore t to its place in the task list */
next_time = tv_ms_remain2(&now, &t->expire); *next = t->expire;
out: out:
/* Ensure that we don't report sub-millisecond timeouts */ return;
if (next_time != TIME_ETERNITY)
next_time++;
return next_time;
} }

View File

@ -1,7 +1,7 @@
/* /*
* Client-side variables and functions. * Client-side variables and 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * 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->rto = s->be->srvtimeout;
s->rep->wto = s->fe->clitimeout; s->rep->wto = s->fe->clitimeout;
s->rep->cto = 0; tv_zero(&s->rep->cto);
fd_insert(cfd); fd_insert(cfd);
fdtab[cfd].owner = t; fdtab[cfd].owner = t;
@ -421,13 +421,13 @@ int event_accept(int fd) {
tv_eternity(&s->rep->wex); tv_eternity(&s->rep->wex);
tv_eternity(&t->expire); tv_eternity(&t->expire);
if (s->fe->clitimeout) { if (tv_isset(&s->fe->clitimeout)) {
if (EV_FD_ISSET(cfd, DIR_RD)) { 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; t->expire = s->req->rex;
} }
if (EV_FD_ISSET(cfd, DIR_WR)) { 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; t->expire = s->req->rex;
} }
} }

View File

@ -220,16 +220,22 @@ REGPRM1 static void __fd_clo(int fd)
/* /*
* epoll() poller * 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 status;
int fd; int fd;
int count; int count;
int wait_time;
if (likely(nbchanges)) if (likely(nbchanges))
fd_flush_changes(); fd_flush_changes();
/* now let's wait for events */ /* 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); status = epoll_wait(epoll_fd, epoll_events, maxfd, wait_time);
tv_now(&now); tv_now(&now);

View File

@ -81,10 +81,11 @@ REGPRM1 static void __fd_rem(const int fd)
/* /*
* Poll() poller * 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 status;
int fd, nbfd; int fd, nbfd;
int wait_time;
int fds, count; int fds, count;
int sr, sw; int sr, sw;
@ -123,6 +124,11 @@ REGPRM2 static void _do_poll(struct poller *p, int wait_time)
} }
/* now let's wait for events */ /* 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); status = poll(poll_events, nbfd, wait_time);
tv_now(&now); tv_now(&now);

View File

@ -78,7 +78,7 @@ REGPRM1 static void __fd_rem(int fd)
/* /*
* Select() poller * 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 status;
int fd, i; 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 */ /* allow select to return immediately when needed */
delta.tv_sec = delta.tv_usec = 0; delta.tv_sec = delta.tv_usec = 0;
if (wait_time > 0) { /* FIXME */ if (tv_isset(exp)) {
/* Convert to timeval */ tv_remain(&now, exp, &delta);
/* to avoid eventual select loops due to timer precision */ /* To avoid eventual select loops due to timer precision */
wait_time += SCHEDULER_RESOLUTION; delta.tv_usec += SCHEDULER_RESOLUTION * 1000;
delta.tv_sec = wait_time / 1000; if (delta.tv_usec >= 1000000) {
delta.tv_usec = (wait_time % 1000) * 1000; delta.tv_usec -= 1000000;
delta.tv_sec ++;
}
} }
/* let's restore fdset state */ /* 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, readnotnull ? tmp_evts[DIR_RD] : NULL,
writenotnull ? tmp_evts[DIR_WR] : NULL, writenotnull ? tmp_evts[DIR_WR] : NULL,
NULL, NULL,
(wait_time >= 0) ? &delta : NULL); tv_isset(exp) ? &delta : NULL);
tv_now(&now); tv_now(&now);

View File

@ -259,13 +259,14 @@ static struct ev_to_epoll {
/* /*
* speculative epoll() poller * 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; static unsigned int last_skipped;
int status; int status;
int fd, opcode; int fd, opcode;
int count; int count;
int spec_idx; int spec_idx;
int wait_time;
/* Here we have two options : /* Here we have two options :
@ -370,6 +371,12 @@ REGPRM2 static void _do_poll(struct poller *p, int wait_time)
} }
wait_time = 0; wait_time = 0;
} }
else {
if (tv_isset(exp))
wait_time = tv_ms_remain(&now, exp);
else
wait_time = -1;
}
last_skipped = 0; last_skipped = 0;
/* now let's wait for events */ /* now let's wait for events */

View File

@ -684,17 +684,17 @@ static void tell_old_pids(int sig)
*/ */
void run_poll_loop() void run_poll_loop()
{ {
int next_time; struct timeval next;
tv_now(&now);
tv_now(&now);
while (1) { 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 */ /* stop when there's no connection left and we don't allow them anymore */
if (!actconn && listeners == 0) if (!actconn && listeners == 0)
break; break;
cur_poller.poll(&cur_poller, next_time); cur_poller.poll(&cur_poller, &next);
} }
} }

View File

@ -442,8 +442,8 @@ void client_retnclose(struct session *s, const struct chunk *msg)
EV_FD_CLR(s->cli_fd, DIR_RD); EV_FD_CLR(s->cli_fd, DIR_RD);
EV_FD_SET(s->cli_fd, DIR_WR); EV_FD_SET(s->cli_fd, DIR_WR);
tv_eternity(&s->req->rex); tv_eternity(&s->req->rex);
if (s->fe->clitimeout) if (tv_isset(&s->fe->clitimeout))
tv_ms_add(&s->rep->wex, &now, s->fe->clitimeout); tv_add(&s->rep->wex, &now, &s->fe->clitimeout);
else else
tv_eternity(&s->rep->wex); tv_eternity(&s->rep->wex);
s->cli_state = CL_STSHUTR; 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 * the time the task accepts to wait, or TIME_ETERNITY for
* infinity. * infinity.
*/ */
int process_session(struct task *t) void process_session(struct task *t, struct timeval *next)
{ {
struct session *s = t->context; struct session *s = t->context;
int fsm_resync = 0; int fsm_resync = 0;
@ -563,11 +563,11 @@ int process_session(struct task *t)
/* DEBUG code : this should never ever happen, otherwise it indicates /* DEBUG code : this should never ever happen, otherwise it indicates
* that a task still has something to do and will provoke a quick loop. * 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); exit(100);
#endif #endif
*next = t->expire;
return tv_ms_remain2(&now, &t->expire); /* nothing more to do */ return; /* nothing more to do */
} }
s->fe->feconn--; s->fe->feconn--;
@ -615,7 +615,7 @@ int process_session(struct task *t)
task_delete(t); task_delete(t);
session_free(s); session_free(s);
task_free(t); 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 ? */ /* 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. */ /* read timeout : give up with an error message. */
txn->status = 408; txn->status = 408;
client_retnclose(t, error_message(t, HTTP_ERR_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 * full. We cannot loop here since stream_sock_read will disable it only if
* req->l == rlim-data * req->l == rlim-data
*/ */
if (t->fe->clitimeout) if (tv_isset(&t->fe->clitimeout))
tv_ms_add(&req->rex, &now, t->fe->clitimeout); tv_add(&req->rex, &now, &t->fe->clitimeout);
else else
tv_eternity(&req->rex); 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); t->logs.t_request = tv_ms_elapsed(&t->logs.tv_accept, &now);
if (!t->fe->clitimeout || if (!tv_isset(&t->fe->clitimeout) ||
(t->srv_state < SV_STDATA && t->be->srvtimeout)) { (t->srv_state < SV_STDATA && tv_isset(&t->be->srvtimeout))) {
/* If the client has no timeout, or if the server is not ready yet, /* 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 * 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 * 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 /* flush the request so that we can drop the connection early
* if the client closes first. * if the client closes first.
*/ */
tv_ms_add(&req->cex, &now, if (tv_isset(&t->be->contimeout))
t->be->contimeout ? t->be->contimeout : 0); tv_add(&req->cex, &now, &t->be->contimeout);
else
req->cex = now;
} }
/* OK let's go on with the BODY 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 /* We must ensure that the read part is still alive when switching
* to shutw */ * to shutw */
EV_FD_SET(t->cli_fd, DIR_RD); EV_FD_SET(t->cli_fd, DIR_RD);
if (t->fe->clitimeout) if (tv_isset(&t->fe->clitimeout))
tv_ms_add(&req->rex, &now, t->fe->clitimeout); tv_add(&req->rex, &now, &t->fe->clitimeout);
t->cli_state = CL_STSHUTW; t->cli_state = CL_STSHUTW;
//fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state); //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
return 1; return 1;
} }
/* read timeout */ /* 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); EV_FD_CLR(t->cli_fd, DIR_RD);
tv_eternity(&req->rex); tv_eternity(&req->rex);
t->cli_state = CL_STSHUTR; t->cli_state = CL_STSHUTR;
@ -2020,15 +2022,15 @@ int process_cli(struct session *t)
return 1; return 1;
} }
/* write timeout */ /* 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); EV_FD_CLR(t->cli_fd, DIR_WR);
tv_eternity(&rep->wex); tv_eternity(&rep->wex);
shutdown(t->cli_fd, SHUT_WR); shutdown(t->cli_fd, SHUT_WR);
/* We must ensure that the read part is still alive when switching /* We must ensure that the read part is still alive when switching
* to shutw */ * to shutw */
EV_FD_SET(t->cli_fd, DIR_RD); EV_FD_SET(t->cli_fd, DIR_RD);
if (t->fe->clitimeout) if (tv_isset(&t->fe->clitimeout))
tv_ms_add(&req->rex, &now, t->fe->clitimeout); tv_add(&req->rex, &now, &t->fe->clitimeout);
t->cli_state = CL_STSHUTW; t->cli_state = CL_STSHUTW;
if (!(t->flags & SN_ERR_MASK)) if (!(t->flags & SN_ERR_MASK))
@ -2053,8 +2055,8 @@ int process_cli(struct session *t)
} else { } else {
/* there's still some space in the buffer */ /* there's still some space in the buffer */
if (EV_FD_COND_S(t->cli_fd, DIR_RD)) { if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
if (!t->fe->clitimeout || if (!tv_isset(&t->fe->clitimeout) ||
(t->srv_state < SV_STDATA && t->be->srvtimeout)) (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 /* 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 * 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 * 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); tv_eternity(&req->rex);
else 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 */ /* buffer not empty */
if (EV_FD_COND_S(t->cli_fd, DIR_WR)) { if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
/* restart writing */ /* restart writing */
if (t->fe->clitimeout) { if (tv_isset(&t->fe->clitimeout)) {
tv_ms_add(&rep->wex, &now, t->fe->clitimeout); tv_add(&rep->wex, &now, &t->fe->clitimeout);
/* FIXME: to prevent the client from expiring read timeouts during writes, /* FIXME: to prevent the client from expiring read timeouts during writes,
* we refresh it. */ * we refresh it. */
req->rex = rep->wex; req->rex = rep->wex;
@ -2112,7 +2114,7 @@ int process_cli(struct session *t)
t->cli_state = CL_STCLOSE; t->cli_state = CL_STCLOSE;
return 1; return 1;
} }
else if (tv_ms_le2(&rep->wex, &now)) { else if (__tv_isle(&rep->wex, &now)) {
tv_eternity(&rep->wex); tv_eternity(&rep->wex);
fd_delete(t->cli_fd); fd_delete(t->cli_fd);
t->cli_state = CL_STCLOSE; t->cli_state = CL_STCLOSE;
@ -2149,8 +2151,8 @@ int process_cli(struct session *t)
/* buffer not empty */ /* buffer not empty */
if (EV_FD_COND_S(t->cli_fd, DIR_WR)) { if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
/* restart writing */ /* restart writing */
if (t->fe->clitimeout) { if (tv_isset(&t->fe->clitimeout)) {
tv_ms_add(&rep->wex, &now, t->fe->clitimeout); tv_add(&rep->wex, &now, &t->fe->clitimeout);
/* FIXME: to prevent the client from expiring read timeouts during writes, /* FIXME: to prevent the client from expiring read timeouts during writes,
* we refresh it. */ * we refresh it. */
req->rex = rep->wex; req->rex = rep->wex;
@ -2184,7 +2186,7 @@ int process_cli(struct session *t)
t->cli_state = CL_STCLOSE; t->cli_state = CL_STCLOSE;
return 1; return 1;
} }
else if (tv_ms_le2(&req->rex, &now)) { else if (__tv_isle(&req->rex, &now)) {
tv_eternity(&req->rex); tv_eternity(&req->rex);
fd_delete(t->cli_fd); fd_delete(t->cli_fd);
t->cli_state = CL_STCLOSE; t->cli_state = CL_STCLOSE;
@ -2215,8 +2217,8 @@ int process_cli(struct session *t)
} else { } else {
/* there's still some space in the buffer */ /* there's still some space in the buffer */
if (EV_FD_COND_S(t->cli_fd, DIR_RD)) { if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
if (t->fe->clitimeout) if (tv_isset(&t->fe->clitimeout))
tv_ms_add(&req->rex, &now, t->fe->clitimeout); tv_add(&req->rex, &now, &t->fe->clitimeout);
else else
tv_eternity(&req->rex); tv_eternity(&req->rex);
//fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state); //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 * already set the connect expiration date to the right
* timeout. We just have to check that it has not expired. * 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; return 0;
/* We will set the queue timer to the time spent, just for /* 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. * to any other session to release it and wake us up again.
*/ */
if (t->pend_pos) { if (t->pend_pos) {
if (!tv_ms_le2(&req->cex, &now)) if (!__tv_isle(&req->cex, &now))
return 0; return 0;
else { else {
/* we've been waiting too long here */ /* 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); srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
return 1; 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); //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 */ return 0; /* nothing changed */
} }
@ -2416,8 +2418,8 @@ int process_srv(struct session *t)
tv_eternity(&req->wex); tv_eternity(&req->wex);
} else /* need the right to write */ { } else /* need the right to write */ {
EV_FD_SET(t->srv_fd, DIR_WR); EV_FD_SET(t->srv_fd, DIR_WR);
if (t->be->srvtimeout) { if (tv_isset(&t->be->srvtimeout)) {
tv_ms_add(&req->wex, &now, t->be->srvtimeout); tv_add(&req->wex, &now, &t->be->srvtimeout);
/* FIXME: to prevent the server from expiring read timeouts during writes, /* FIXME: to prevent the server from expiring read timeouts during writes,
* we refresh it. */ * we refresh it. */
rep->rex = req->wex; 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 */ if (t->be->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
EV_FD_SET(t->srv_fd, DIR_RD); EV_FD_SET(t->srv_fd, DIR_RD);
if (t->be->srvtimeout) if (tv_isset(&t->be->srvtimeout))
tv_ms_add(&rep->rex, &now, t->be->srvtimeout); tv_add(&rep->rex, &now, &t->be->srvtimeout);
else else
tv_eternity(&rep->rex); 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 * full. We cannot loop here since stream_sock_read will disable it only if
* rep->l == rlim-data * rep->l == rlim-data
*/ */
if (t->be->srvtimeout) if (tv_isset(&t->be->srvtimeout))
tv_ms_add(&rep->rex, &now, t->be->srvtimeout); tv_add(&rep->rex, &now, &t->be->srvtimeout);
else else
tv_eternity(&rep->rex); tv_eternity(&rep->rex);
} }
@ -2584,7 +2586,7 @@ int process_srv(struct session *t)
/* read timeout : return a 504 to the client. /* read timeout : return a 504 to the client.
*/ */
else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_RD) && 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(&rep->rex);
tv_eternity(&req->wex); tv_eternity(&req->wex);
fd_delete(t->srv_fd); fd_delete(t->srv_fd);
@ -2624,8 +2626,8 @@ int process_srv(struct session *t)
/* We must ensure that the read part is still /* We must ensure that the read part is still
* alive when switching to shutw */ * alive when switching to shutw */
EV_FD_SET(t->srv_fd, DIR_RD); EV_FD_SET(t->srv_fd, DIR_RD);
if (t->be->srvtimeout) if (tv_isset(&t->be->srvtimeout))
tv_ms_add(&rep->rex, &now, t->be->srvtimeout); tv_add(&rep->rex, &now, &t->be->srvtimeout);
shutdown(t->srv_fd, SHUT_WR); shutdown(t->srv_fd, SHUT_WR);
t->srv_state = SV_STSHUTW; t->srv_state = SV_STSHUTW;
@ -2638,15 +2640,15 @@ int process_srv(struct session *t)
* some work to do on the headers. * some work to do on the headers.
*/ */
else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_WR) && 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); EV_FD_CLR(t->srv_fd, DIR_WR);
tv_eternity(&req->wex); tv_eternity(&req->wex);
shutdown(t->srv_fd, SHUT_WR); shutdown(t->srv_fd, SHUT_WR);
/* We must ensure that the read part is still alive /* We must ensure that the read part is still alive
* when switching to shutw */ * when switching to shutw */
EV_FD_SET(t->srv_fd, DIR_RD); EV_FD_SET(t->srv_fd, DIR_RD);
if (t->be->srvtimeout) if (tv_isset(&t->be->srvtimeout))
tv_ms_add(&rep->rex, &now, t->be->srvtimeout); tv_add(&rep->rex, &now, &t->be->srvtimeout);
t->srv_state = SV_STSHUTW; t->srv_state = SV_STSHUTW;
if (!(t->flags & SN_ERR_MASK)) if (!(t->flags & SN_ERR_MASK))
@ -2667,8 +2669,8 @@ int process_srv(struct session *t)
else if (likely(req->l)) { else if (likely(req->l)) {
if (EV_FD_COND_S(t->srv_fd, DIR_WR)) { if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
/* restart writing */ /* restart writing */
if (t->be->srvtimeout) { if (tv_isset(&t->be->srvtimeout)) {
tv_ms_add(&req->wex, &now, t->be->srvtimeout); tv_add(&req->wex, &now, &t->be->srvtimeout);
/* FIXME: to prevent the server from expiring read timeouts during writes, /* FIXME: to prevent the server from expiring read timeouts during writes,
* we refresh it. */ * we refresh it. */
rep->rex = req->wex; 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 /* We must ensure that the read part is still alive when switching
* to shutw */ * to shutw */
EV_FD_SET(t->srv_fd, DIR_RD); EV_FD_SET(t->srv_fd, DIR_RD);
if (t->be->srvtimeout) if (tv_isset(&t->be->srvtimeout))
tv_ms_add(&rep->rex, &now, t->be->srvtimeout); tv_add(&rep->rex, &now, &t->be->srvtimeout);
shutdown(t->srv_fd, SHUT_WR); shutdown(t->srv_fd, SHUT_WR);
t->srv_state = SV_STSHUTW; 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 /* We must ensure that the read part is still alive when switching
* to shutw */ * to shutw */
EV_FD_SET(t->srv_fd, DIR_RD); EV_FD_SET(t->srv_fd, DIR_RD);
if (t->be->srvtimeout) if (tv_isset(&t->be->srvtimeout))
tv_ms_add(&rep->rex, &now, t->be->srvtimeout); tv_add(&rep->rex, &now, &t->be->srvtimeout);
t->srv_state = SV_STSHUTW; t->srv_state = SV_STSHUTW;
return 1; return 1;
} }
/* read timeout */ /* 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); EV_FD_CLR(t->srv_fd, DIR_RD);
tv_eternity(&rep->rex); tv_eternity(&rep->rex);
t->srv_state = SV_STSHUTR; t->srv_state = SV_STSHUTR;
@ -3052,15 +3054,15 @@ int process_srv(struct session *t)
return 1; return 1;
} }
/* write timeout */ /* 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); EV_FD_CLR(t->srv_fd, DIR_WR);
tv_eternity(&req->wex); tv_eternity(&req->wex);
shutdown(t->srv_fd, SHUT_WR); shutdown(t->srv_fd, SHUT_WR);
/* We must ensure that the read part is still alive when switching /* We must ensure that the read part is still alive when switching
* to shutw */ * to shutw */
EV_FD_SET(t->srv_fd, DIR_RD); EV_FD_SET(t->srv_fd, DIR_RD);
if (t->be->srvtimeout) if (tv_isset(&t->be->srvtimeout))
tv_ms_add(&rep->rex, &now, t->be->srvtimeout); tv_add(&rep->rex, &now, &t->be->srvtimeout);
t->srv_state = SV_STSHUTW; t->srv_state = SV_STSHUTW;
if (!(t->flags & SN_ERR_MASK)) if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_SRVTO; 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 */ else { /* buffer not empty, there are still data to be transferred */
if (EV_FD_COND_S(t->srv_fd, DIR_WR)) { if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
/* restart writing */ /* restart writing */
if (t->be->srvtimeout) { if (tv_isset(&t->be->srvtimeout)) {
tv_ms_add(&req->wex, &now, t->be->srvtimeout); tv_add(&req->wex, &now, &t->be->srvtimeout);
/* FIXME: to prevent the server from expiring read timeouts during writes, /* FIXME: to prevent the server from expiring read timeouts during writes,
* we refresh it. */ * we refresh it. */
rep->rex = req->wex; rep->rex = req->wex;
@ -3098,8 +3100,8 @@ int process_srv(struct session *t)
} }
else { else {
if (EV_FD_COND_S(t->srv_fd, DIR_RD)) { if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
if (t->be->srvtimeout) if (tv_isset(&t->be->srvtimeout))
tv_ms_add(&rep->rex, &now, t->be->srvtimeout); tv_add(&rep->rex, &now, &t->be->srvtimeout);
else else
tv_eternity(&rep->rex); tv_eternity(&rep->rex);
} }
@ -3147,7 +3149,7 @@ int process_srv(struct session *t)
return 1; 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); //EV_FD_CLR(t->srv_fd, DIR_WR);
tv_eternity(&req->wex); tv_eternity(&req->wex);
fd_delete(t->srv_fd); fd_delete(t->srv_fd);
@ -3176,8 +3178,8 @@ int process_srv(struct session *t)
else { /* buffer not empty */ else { /* buffer not empty */
if (EV_FD_COND_S(t->srv_fd, DIR_WR)) { if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
/* restart writing */ /* restart writing */
if (t->be->srvtimeout) { if (tv_isset(&t->be->srvtimeout)) {
tv_ms_add(&req->wex, &now, t->be->srvtimeout); tv_add(&req->wex, &now, &t->be->srvtimeout);
/* FIXME: to prevent the server from expiring read timeouts during writes, /* FIXME: to prevent the server from expiring read timeouts during writes,
* we refresh it. */ * we refresh it. */
rep->rex = req->wex; rep->rex = req->wex;
@ -3228,7 +3230,7 @@ int process_srv(struct session *t)
return 1; 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); //EV_FD_CLR(t->srv_fd, DIR_RD);
tv_eternity(&rep->rex); tv_eternity(&rep->rex);
fd_delete(t->srv_fd); fd_delete(t->srv_fd);
@ -3255,8 +3257,8 @@ int process_srv(struct session *t)
} }
else { else {
if (EV_FD_COND_S(t->srv_fd, DIR_RD)) { if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
if (t->be->srvtimeout) if (tv_isset(&t->be->srvtimeout))
tv_ms_add(&rep->rex, &now, t->be->srvtimeout); tv_add(&rep->rex, &now, &t->be->srvtimeout);
else else
tv_eternity(&rep->rex); tv_eternity(&rep->rex);
} }
@ -4375,7 +4377,7 @@ void manage_client_side_cookies(struct session *t, struct buffer *req)
}/* end while(srv) */ }/* end while(srv) */
}/* end else if server == NULL */ }/* 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) ... */ }/* 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') if (asession_temp->serverid[0] == '\0')
memcpy(asession_temp->serverid, t->srv->id, server_id_len); 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) #if defined(DEBUG_HASH)
print_table(&(t->be->htbl_proxy)); 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); 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++; asession_temp->request_count++;
#if defined(DEBUG_HASH) #if defined(DEBUG_HASH)

View File

@ -1,7 +1,7 @@
/* /*
* Proxy variables and functions. * Proxy variables and 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * 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, * 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 * 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 * select_loop(). It returns the date of next expiration event during stop
* during stop time, TIME_ETERNITY otherwise. * time, ETERNITY otherwise.
*/ */
int maintain_proxies(void) void maintain_proxies(struct timeval *next)
{ {
struct proxy *p; struct proxy *p;
struct listener *l; struct listener *l;
int tleft; /* time left */
p = proxy; p = proxy;
tleft = TIME_ETERNITY; /* infinite time */ tv_eternity(next);
/* if there are enough free sessions, we'll activate proxies */ /* if there are enough free sessions, we'll activate proxies */
if (actconn < global.maxconn) { if (actconn < global.maxconn) {
@ -233,13 +232,13 @@ int maintain_proxies(void)
p->state = PR_STSTOPPED; p->state = PR_STSTOPPED;
} }
else { else {
tleft = MINTIME(t, tleft); tv_bound(next, &p->stop_time);
} }
} }
p = p->next; p = p->next;
} }
} }
return tleft; return;
} }

View File

@ -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 * 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 * 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 server *s = (struct server*)t->context;
struct proxy *p = s->proxy; struct proxy *p = s->proxy;
@ -65,7 +65,7 @@ int process_srv_queue(struct task *t)
task_wakeup(sess->task); task_wakeup(sess->task);
} }
return TIME_ETERNITY; tv_eternity(next);
} }
/* Detaches the next pending connection from either a server or a proxy, and /* Detaches the next pending connection from either a server or a proxy, and

View File

@ -165,8 +165,8 @@ int stream_sock_read(int fd) {
*/ */
if (b->flags & BF_PARTIAL_READ) { if (b->flags & BF_PARTIAL_READ) {
if (b->rto) { if (tv_isset(&b->rto)) {
tv_ms_add(&b->rex, &now, b->rto); tv_add(&b->rex, &now, &b->rto);
goto out_wakeup; goto out_wakeup;
} }
out_eternity: out_eternity:
@ -315,8 +315,8 @@ int stream_sock_write(int fd) {
*/ */
if (b->flags & BF_PARTIAL_WRITE) { if (b->flags & BF_PARTIAL_WRITE) {
if (b->wto) { if (tv_isset(&b->wto)) {
tv_ms_add(&b->wex, &now, b->wto); tv_add(&b->wex, &now, &b->wto);
/* FIXME: to prevent the client from expiring read timeouts during writes, /* 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 * 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 * unique one, although that needs some study particularly on full-duplex

View File

@ -15,6 +15,7 @@
#include <common/standard.h> #include <common/standard.h>
#include <common/time.h> #include <common/time.h>
#include <proto/proxy.h>
#include <proto/task.h> #include <proto/task.h>
#include <types/task.h> #include <types/task.h>
@ -23,9 +24,6 @@
#include <import/tree.h> #include <import/tree.h>
/* FIXME : this should be removed very quickly ! */
extern int maintain_proxies(void);
void **pool_task= NULL; void **pool_task= NULL;
void **pool_tree64 = NULL; void **pool_tree64 = NULL;
static struct ultree *stack[LLONGBITS]; static struct ultree *stack[LLONGBITS];
@ -47,6 +45,7 @@ struct task *_task_wakeup(struct task *t)
{ {
return __task_wakeup(t); return __task_wakeup(t);
} }
/* /*
* task_queue() * 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 * Extract all expired timers from the wait queue, and wakes up all
* associated tasks. * associated tasks. Returns the date of next event (or eternity).
* Returns the time to wait for next task (next_time).
*
* FIXME: Use an alternative queue for ETERNITY tasks.
* *
*/ */
int wake_expired_tasks() void wake_expired_tasks(struct timeval *next)
{ {
__label__ out; __label__ out;
int slen; int slen;
struct task *task; struct task *task;
void *data; void *data;
int next_time;
/* /*
* Hint: tasks are *rarely* expired. So we can try to optimize * 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)) { if (likely(timer_wq.data != NULL)) {
task = LIST_ELEM(timer_wq.data, struct task *, qlist); task = LIST_ELEM(timer_wq.data, struct task *, qlist);
if (likely(__tv_isge(&task->expire, &now) > 0)) { if (likely(__tv_isge(&task->expire, &now) > 0)) {
next_time = tv_ms_remain(&now, &task->expire); __tv_remain(&now, &task->expire, next);
goto out; goto out;
} }
} }
/* OK we lose. Let's scan the tree then. */ /* OK we lose. Let's scan the tree then. */
next_time = TIME_ETERNITY; tv_eternity(next);
tree64_foreach(&timer_wq, data, stack, slen) { tree64_foreach(&timer_wq, data, stack, slen) {
task = LIST_ELEM(data, struct task *, qlist); task = LIST_ELEM(data, struct task *, qlist);
if (__tv_isgt(&task->expire, &now)) { if (__tv_isgt(&task->expire, &now)) {
next_time = tv_ms_remain(&now, &task->expire); __tv_remain2(&now, &task->expire, next);
break; break;
} }
@ -131,10 +126,7 @@ int wake_expired_tasks()
} }
} }
out: out:
/* Ensure that we don't report sub-millisecond timeouts */ return;
if (next_time != TIME_ETERNITY)
next_time++;
return next_time;
} }
/* /*
@ -142,17 +134,16 @@ int wake_expired_tasks()
* - wake up all expired tasks * - wake up all expired tasks
* - call all runnable tasks * - call all runnable tasks
* - call maintain_proxies() to enable/disable the listeners * - 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 <next> or eternity.
* *
*/ */
int process_runnable_tasks() void process_runnable_tasks(struct timeval *next)
{ {
int next_time; struct timeval temp;
int time2;
struct task *t; struct task *t;
void *queue; void *queue;
next_time = wake_expired_tasks(); wake_expired_tasks(next);
/* process each task in the run queue now. Each task may be deleted /* 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 * 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 * woken up by any other task and it will be processed immediately
@ -161,21 +152,20 @@ int process_runnable_tasks()
queue = run_queue; queue = run_queue;
foreach_dlist_item(t, queue, struct task *, qlist) { foreach_dlist_item(t, queue, struct task *, qlist) {
int temp_time;
DLIST_DEL(&t->qlist); DLIST_DEL(&t->qlist);
t->qlist.p = NULL; t->qlist.p = NULL;
t->state = TASK_IDLE; t->state = TASK_IDLE;
temp_time = t->process(t); t->process(t, &temp);
next_time = MINTIME(temp_time, next_time); tv_bound(next, &temp);
} }
/* maintain all proxies in a consistent state. This should quickly /* maintain all proxies in a consistent state. This should quickly
* become a task because it becomes expensive when there are huge * become a task because it becomes expensive when there are huge
* numbers of proxies. */ * numbers of proxies. */
time2 = maintain_proxies(); maintain_proxies(&temp);
return MINTIME(time2, next_time); tv_bound(next, &temp);
return;
} }
/* /*

View File

@ -94,6 +94,33 @@ REGPRM2 unsigned long _tv_ms_elapsed(const struct timeval *tv1, const struct tim
return __tv_ms_elapsed(tv1, tv2); return __tv_ms_elapsed(tv1, tv2);
} }
/*
* adds <inc> to <from>, set the result to <tv> and returns a pointer <tv>
*/
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: * Local variables:
* c-indent-level: 8 * c-indent-level: 8