[MEDIUM] minor update to the task api: let the scheduler queue itself
All the tasks callbacks had to requeue the task themselves, and update
a global timeout. This was not convenient at all. Now the API has been
simplified. The tasks callbacks only have to update their expire timer,
and return either a pointer to the task or NULL if the task has been
deleted. The scheduler will take care of requeuing the task at the
proper place in the wait queue.
diff --git a/include/common/appsession.h b/include/common/appsession.h
index 616766f..6c12926 100644
--- a/include/common/appsession.h
+++ b/include/common/appsession.h
@@ -38,7 +38,7 @@
/* Callback for destroy */
void destroy(appsess *data);
-void appsession_refresh(struct task *t, int *next);
+struct task *appsession_refresh(struct task *t);
int appsession_task_init(void);
int appsession_init(void);
void appsession_cleanup(void);
diff --git a/include/proto/checks.h b/include/proto/checks.h
index 8499175..6f0aa8b 100644
--- a/include/proto/checks.h
+++ b/include/proto/checks.h
@@ -2,7 +2,7 @@
include/proto/checks.h
Functions prototypes for the checks.
- Copyright (C) 2000-2007 Willy Tarreau - w@1wt.eu
+ Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -25,7 +25,7 @@
#include <types/task.h>
#include <common/config.h>
-void process_chk(struct task *t, struct timeval *next);
+struct task *process_chk(struct task *t);
int start_checks();
#endif /* _PROTO_CHECKS_H */
diff --git a/include/proto/proto_uxst.h b/include/proto/proto_uxst.h
index e770942..bf487b6 100644
--- a/include/proto/proto_uxst.h
+++ b/include/proto/proto_uxst.h
@@ -28,8 +28,7 @@
int uxst_event_accept(int fd);
void uxst_add_listener(struct listener *listener);
-void process_uxst_stats(struct task *t, int *next);
-void uxst_process_session(struct task *t, int *next);
+struct task *uxst_process_session(struct task *t);
#endif /* _PROTO_PROTO_UXST_H */
diff --git a/include/proto/session.h b/include/proto/session.h
index ad0a57e..7cc50f6 100644
--- a/include/proto/session.h
+++ b/include/proto/session.h
@@ -36,7 +36,7 @@
void session_process_counters(struct session *s);
void sess_change_server(struct session *sess, struct server *newsrv);
-void process_session(struct task *t, int *next);
+struct task *process_session(struct task *t);
static void inline trace_term(struct session *s, unsigned int code)
{
diff --git a/include/types/protocols.h b/include/types/protocols.h
index 5c3b608..e91fdb3 100644
--- a/include/types/protocols.h
+++ b/include/types/protocols.h
@@ -85,7 +85,7 @@
struct listener *next; /* next address for the same proxy, or NULL */
struct list proto_list; /* list in the protocol header */
int (*accept)(int fd); /* accept() function passed to fdtab[] */
- void (*handler)(struct task *t, int *next); /* protocol handler */
+ struct task * (*handler)(struct task *t); /* protocol handler. It is a task */
int *timeout; /* pointer to client-side timeout */
void *private; /* any private data which may be used by accept() */
unsigned int analysers; /* bitmap of required protocol analysers */
diff --git a/include/types/task.h b/include/types/task.h
index 4302ec0..1cc12a9 100644
--- a/include/types/task.h
+++ b/include/types/task.h
@@ -50,11 +50,18 @@
struct eb32_node rq; /* ebtree node used to hold the task in the run queue */
int state; /* task state : bit field of TASK_* */
unsigned int expire; /* next expiration time for this task */
- void (*process)(struct task *t, int *next); /* the function which processes the task */
+ struct task * (*process)(struct task *t); /* the function which processes the task */
void *context; /* the task's context */
int nice; /* the task's current nice value from -1024 to +1024 */
};
+/*
+ * The task callback (->process) is responsible for updating ->expire. It must
+ * return a pointer to the task itself, except if the task has been deleted, in
+ * which case it returns NULL so that the scheduler knows it must not check the
+ * expire timer. The scheduler will requeue the task at the proper location.
+ */
+
#endif /* _TYPES_TASK_H */
/*
diff --git a/src/appsession.c b/src/appsession.c
index 45050b5..a1c1c88 100644
--- a/src/appsession.c
+++ b/src/appsession.c
@@ -2,7 +2,7 @@
* AppSession functions.
*
* Copyright 2004-2006 Alexander Lazic, Klaus Wagner
- * Copyright 2006-2007 Willy Tarreau
+ * Copyright 2006-2009 Willy Tarreau
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -100,7 +100,7 @@
return 0;
}
-void appsession_refresh(struct task *t, int *next)
+struct task *appsession_refresh(struct task *t)
{
struct proxy *p = proxy;
struct appsession_hash *htbl;
@@ -131,8 +131,7 @@
p = p->next;
}
t->expire = tick_add(now_ms, MS_TO_TICKS(TBLCHKINT)); /* check expiration every 5 seconds */
- task_queue(t);
- *next = t->expire;
+ return t;
} /* end appsession_refresh */
int match_str(const void *key1, const void *key2)
diff --git a/src/checks.c b/src/checks.c
index 37e0c29..f1e8120 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -1,7 +1,7 @@
/*
* Health-checks functions.
*
- * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
* Copyright 2007-2008 Krzysztof Piotr Oledzki <ole@ans.pl>
*
* This program is free software; you can redistribute it and/or
@@ -522,9 +522,8 @@
* manages a server health-check. Returns
* the time the task accepts to wait, or TIME_ETERNITY for infinity.
*/
-void process_chk(struct task *t, int *next)
+struct task *process_chk(struct task *t)
{
- __label__ new_chk, out;
struct server *s = t->context;
struct sockaddr_in sa;
int fd;
@@ -536,11 +535,8 @@
fd = s->curfd;
if (fd < 0) { /* no check currently running */
//fprintf(stderr, "process_chk: 2\n");
- if (!tick_is_expired(t->expire, now_ms)) { /* not good time yet */
- task_queue(t); /* restore t to its place in the task list */
- *next = t->expire;
- goto out;
- }
+ if (!tick_is_expired(t->expire, now_ms)) /* woke up too early */
+ return t;
/* we don't send any health-checks when the proxy is stopped or when
* the server should not be checked.
@@ -548,9 +544,7 @@
if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
while (tick_is_expired(t->expire, now_ms))
t->expire = tick_add(t->expire, MS_TO_TICKS(s->inter));
- task_queue(t); /* restore t to its place in the task list */
- *next = t->expire;
- goto out;
+ return t;
}
/* we'll initiate a new check */
@@ -674,10 +668,7 @@
int t_con = tick_add(now_ms, s->proxy->timeout.connect);
t->expire = tick_first(t->expire, t_con);
}
-
- task_queue(t); /* restore t to its place in the task list */
- *next = t->expire;
- return;
+ return t;
}
else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
s->result |= SRV_CHK_ERROR; /* a real error */
@@ -797,10 +788,7 @@
}
//fprintf(stderr, "process_chk: 11\n");
s->result = SRV_CHK_UNKNOWN;
- task_queue(t); /* restore t to its place in the task list */
- *next = t->expire;
- out:
- return;
+ return t;
}
/*
diff --git a/src/proto_uxst.c b/src/proto_uxst.c
index 4b24209..6351ef1 100644
--- a/src/proto_uxst.c
+++ b/src/proto_uxst.c
@@ -708,7 +708,7 @@
* still exists but remains in SI_ST_INI state forever, so that any call is a
* NOP.
*/
-void uxst_process_session(struct task *t, int *next)
+struct task *uxst_process_session(struct task *t)
{
struct session *s = t->context;
int resync;
@@ -969,11 +969,7 @@
if (s->si[0].exp)
t->expire = tick_first(t->expire, s->si[0].exp);
- /* restore t to its place in the task list */
- task_queue(t);
-
- *next = t->expire;
- return; /* nothing more to do */
+ return t;
}
actconn--;
@@ -988,10 +984,10 @@
}
/* the task MUST not be in the run queue anymore */
- task_delete(t);
session_free(s);
+ task_delete(t);
task_free(t);
- *next = TICK_ETERNITY;
+ return NULL;
}
__attribute__((constructor))
diff --git a/src/session.c b/src/session.c
index bcfa5c1..7d7b4b6 100644
--- a/src/session.c
+++ b/src/session.c
@@ -554,7 +554,7 @@
* and each function is called only if at least another function has changed at
* least one flag it is interested in.
*/
-void process_session(struct task *t, int *next)
+struct task *process_session(struct task *t)
{
struct session *s = t->context;
int resync;
@@ -1029,16 +1029,13 @@
fprintf(stderr, "[%u] queuing with exp=%u req->rex=%u req->wex=%u req->ana_exp=%u rep->rex=%u rep->wex=%u, cs=%d, ss=%d\n",
now_ms, t->expire, s->req->rex, s->req->wex, s->req->analyse_exp, s->rep->rex, s->rep->wex, s->si[0].state, s->si[1].state);
#endif
- /* restore t to its place in the task list */
- task_queue(t);
#ifdef DEBUG_DEV
/* this may only happen when no timeout is set or in case of an FSM bug */
if (!t->expire)
ABORT_NOW();
#endif
- *next = t->expire;
- return; /* nothing more to do */
+ return t; /* nothing more to do */
}
s->fe->feconn--;
@@ -1066,10 +1063,10 @@
}
/* the task MUST not be in the run queue anymore */
- task_delete(t);
session_free(s);
+ task_delete(t);
task_free(t);
- *next = TICK_ETERNITY;
+ return NULL;
}
/*
diff --git a/src/task.c b/src/task.c
index fde9112..844862e 100644
--- a/src/task.c
+++ b/src/task.c
@@ -295,11 +295,11 @@
*/
void process_runnable_tasks(int *next)
{
- int temp;
struct task *t;
struct eb32_node *eb;
unsigned int tree, stop;
unsigned int max_processed;
+ int expire;
if (!run_queue)
return;
@@ -315,6 +315,7 @@
stop = (tree + TIMER_TREES / 2) & TIMER_TREE_MASK;
tree = (tree - 1) & TIMER_TREE_MASK;
+ expire = *next;
do {
eb = eb32_first(&rqueue[tree]);
while (eb) {
@@ -325,15 +326,19 @@
__task_unlink_rq(t);
t->state |= TASK_RUNNING;
- t->process(t, &temp);
- t->state &= ~TASK_RUNNING;
- *next = tick_first(*next, temp);
+ if (likely(t->process(t) != NULL)) {
+ t->state &= ~TASK_RUNNING;
+ expire = tick_first(expire, t->expire);
+ task_queue(t);
+ }
if (!--max_processed)
- return;
+ goto out;
}
tree = (tree + 1) & TIMER_TREE_MASK;
} while (tree != stop);
+ out:
+ *next = expire;
}
/* perform minimal intializations, report 0 in case of error, 1 if OK. */