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);
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
#include <types/task.h>
#include <common/config.h>
-int process_chk(struct task *t);
+void process_chk(struct task *t, struct timeval *next);
#endif /* _PROTO_CHECKS_H */
#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);
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
#define _PROTO_PROXY_H
#include <common/config.h>
+#include <common/time.h>
#include <types/proxy.h>
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);
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
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);
* - 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 <next> or eternity.
*/
-int process_runnable_tasks();
+void process_runnable_tasks(struct timeval *next);
#endif /* _PROTO_TASK_H */
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 */
* 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 <exp>
*/
struct poller {
void *private; /* any private data for the poller */
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 (*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 */
void REGPRM1 (*term)(struct poller *p); /* termination of this poller */
int REGPRM1 (*test)(struct poller *p); /* pre-init check of the poller */
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 */
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 */
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
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 */
};
return 0;
}
-int appsession_refresh(struct task *t)
+void appsession_refresh(struct task *t, struct timeval *next)
{
struct proxy *p = proxy;
CHTbl *htbl;
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;
}
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)) */
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)
/*
* 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
* modify it under the terms of the GNU General Public License
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 */
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;
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");
}
}
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;
}
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;
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;
}
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))
}
}
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"
/*
* 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
* modify it under the terms of the GNU General Public License
* 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);
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;
}
* 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;
}
/* 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);
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 */
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 */
}
//fprintf(stderr, "process_chk: 7\n");
/* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
- while (tv_ms_le2(&t->expire, &now))
+ while (__tv_isle(&t->expire, &now))
tv_ms_add(&t->expire, &t->expire, s->inter);
goto new_chk;
}
}
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) {
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;
}
//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;
}
/*
* 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
* modify it under the terms of the GNU General Public License
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;
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;
}
}
/*
* 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);
/*
* 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;
}
/* 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);
/*
* 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;
/* 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 */
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);
/*
* 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 :
}
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 */
*/
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);
}
}
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;
* 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;
/* 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--;
task_delete(t);
session_free(s);
task_free(t);
- return TIME_ETERNITY; /* rest in peace for eternity */
+ tv_eternity(next);
}
}
/* 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));
* 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);
}
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
/* 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 */
/* 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;
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))
} 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
*/
tv_eternity(&req->rex);
else
- tv_ms_add(&req->rex, &now, t->fe->clitimeout);
+ tv_add(&req->rex, &now, &t->fe->clitimeout);
}
}
/* 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;
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;
/* 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;
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;
} 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);
* 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
* 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 */
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 */
}
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;
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);
* 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);
}
/* 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);
/* 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;
* 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))
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;
/* 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;
/* 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;
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;
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;
}
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);
}
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);
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;
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);
}
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);
}
}/* 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) ... */
}
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));
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)
/*
* 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
* modify it under the terms of the GNU General Public License
/*
* 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) {
p->state = PR_STSTOPPED;
}
else {
- tleft = MINTIME(t, tleft);
+ tv_bound(next, &p->stop_time);
}
}
p = p->next;
}
}
- return tleft;
+ return;
}
/*
* 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;
task_wakeup(sess->task);
}
- return TIME_ETERNITY;
+ tv_eternity(next);
}
/* Detaches the next pending connection from either a server or a proxy, and
*/
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:
*/
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
#include <common/standard.h>
#include <common/time.h>
+#include <proto/proxy.h>
#include <proto/task.h>
#include <types/task.h>
#include <import/tree.h>
-/* 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];
{
return __task_wakeup(t);
}
+
/*
* task_queue()
*
/*
* 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
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;
}
}
}
out:
- /* Ensure that we don't report sub-millisecond timeouts */
- if (next_time != TIME_ETERNITY)
- next_time++;
- return next_time;
+ return;
}
/*
* - 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 <next> 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
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;
}
/*
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:
* c-indent-level: 8