blob: 86a3c3d8151d712912a93f45f4f1070b93a7ef2d [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 include/proto/task.h
3 Functions for task management.
4
Willy Tarreau4726f532009-03-07 17:25:21 +01005 Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu
Willy Tarreaubaaee002006-06-26 02:48:02 +02006
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation, version 2.1
10 exclusively.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20*/
21
22#ifndef _PROTO_TASK_H
23#define _PROTO_TASK_H
24
25
26#include <sys/time.h>
Willy Tarreaue3ba5f02006-06-29 18:54:54 +020027
28#include <common/config.h>
Willy Tarreau26ca34e2009-03-21 12:51:40 +010029#include <common/eb32tree.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020030#include <common/memory.h>
Willy Tarreau96bcfd72007-04-29 10:41:56 +020031#include <common/mini-clist.h>
32#include <common/standard.h>
Willy Tarreaud0a201b2009-03-08 15:53:06 +010033#include <common/ticks.h>
Willy Tarreau96bcfd72007-04-29 10:41:56 +020034
Willy Tarreaue3ba5f02006-06-29 18:54:54 +020035#include <types/task.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020036
Willy Tarreaud0a201b2009-03-08 15:53:06 +010037/* Principle of the wait queue.
38 *
39 * We want to be able to tell whether an expiration date is before of after the
40 * current time <now>. We KNOW that expiration dates are never too far apart,
41 * because they are measured in ticks (milliseconds). We also know that almost
42 * all dates will be in the future, and that a very small part of them will be
43 * in the past, they are the ones which have expired since last time we checked
44 * them. Using ticks, we know if a date is in the future or in the past, but we
45 * cannot use that to store sorted information because that reference changes
46 * all the time.
47 *
Willy Tarreaue35c94a2009-03-21 10:01:42 +010048 * We'll use the fact that the time wraps to sort timers. Timers above <now>
49 * are in the future, timers below <now> are in the past. Here, "above" and
50 * "below" are to be considered modulo 2^31.
Willy Tarreaud0a201b2009-03-08 15:53:06 +010051 *
Willy Tarreaue35c94a2009-03-21 10:01:42 +010052 * Timers are stored sorted in an ebtree. We use the new ability for ebtrees to
53 * lookup values starting from X to only expire tasks between <now> - 2^31 and
54 * <now>. If the end of the tree is reached while walking over it, we simply
55 * loop back to the beginning. That way, we have no problem keeping sorted
56 * wrapping timers in a tree, between (now - 24 days) and (now + 24 days). The
57 * keys in the tree always reflect their real position, none can be infinite.
58 * This reduces the number of checks to be performed.
Willy Tarreaud0a201b2009-03-08 15:53:06 +010059 *
60 * Another nice optimisation is to allow a timer to stay at an old place in the
61 * queue as long as it's not further than the real expiration date. That way,
62 * we use the tree as a place holder for a minorant of the real expiration
63 * date. Since we have a very low chance of hitting a timeout anyway, we can
64 * bounce the nodes to their right place when we scan the tree if we encounter
65 * a misplaced node once in a while. This even allows us not to remove the
66 * infinite timers from the wait queue.
67 *
68 * So, to summarize, we have :
69 * - node->key always defines current position in the wait queue
70 * - timer is the real expiration date (possibly infinite)
Willy Tarreaue35c94a2009-03-21 10:01:42 +010071 * - node->key is always before or equal to timer
Willy Tarreaud0a201b2009-03-08 15:53:06 +010072 *
73 * The run queue works similarly to the wait queue except that the current date
74 * is replaced by an insertion counter which can also wrap without any problem.
75 */
76
Willy Tarreaue35c94a2009-03-21 10:01:42 +010077/* The farthest we can look back in a timer tree */
78#define TIMER_LOOK_BACK (1U << 31)
Willy Tarreaud0a201b2009-03-08 15:53:06 +010079
80/* a few exported variables */
Willy Tarreau91e99932008-06-30 07:51:00 +020081extern unsigned int run_queue; /* run queue size */
82extern unsigned int niced_tasks; /* number of niced tasks in the run queue */
Willy Tarreauc6ca1a02007-05-13 19:43:47 +020083extern struct pool_head *pool2_task;
Willy Tarreau26ca34e2009-03-21 12:51:40 +010084extern struct eb32_node *last_timer; /* optimization: last queued timer */
Willy Tarreauc6ca1a02007-05-13 19:43:47 +020085
Willy Tarreau4726f532009-03-07 17:25:21 +010086/* return 0 if task is in run queue, otherwise non-zero */
87static inline int task_in_rq(struct task *t)
88{
89 return t->rq.node.leaf_p != NULL;
90}
91
92/* return 0 if task is in wait queue, otherwise non-zero */
93static inline int task_in_wq(struct task *t)
94{
95 return t->wq.node.leaf_p != NULL;
96}
97
Willy Tarreaufdccded2008-08-29 18:19:04 +020098/* puts the task <t> in run queue with reason flags <f>, and returns <t> */
Willy Tarreau4df82062008-08-29 15:26:14 +020099struct task *__task_wakeup(struct task *t);
Willy Tarreaufdccded2008-08-29 18:19:04 +0200100static inline struct task *task_wakeup(struct task *t, unsigned int f)
Willy Tarreau4df82062008-08-29 15:26:14 +0200101{
Willy Tarreau4726f532009-03-07 17:25:21 +0100102 if (likely(!task_in_rq(t)))
Willy Tarreaufdccded2008-08-29 18:19:04 +0200103 __task_wakeup(t);
104 t->state |= f;
105 return t;
Willy Tarreau4df82062008-08-29 15:26:14 +0200106}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200107
Willy Tarreau4726f532009-03-07 17:25:21 +0100108/*
109 * Unlink the task from the wait queue, and possibly update the last_timer
110 * pointer. A pointer to the task itself is returned. The task *must* already
111 * be in the wait queue before calling this function. If unsure, use the safer
112 * task_unlink_wq() function.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200113 */
Willy Tarreau4726f532009-03-07 17:25:21 +0100114static inline struct task *__task_unlink_wq(struct task *t)
115{
116 eb32_delete(&t->wq);
Willy Tarreau26ca34e2009-03-21 12:51:40 +0100117 if (last_timer == &t->wq)
Willy Tarreau4726f532009-03-07 17:25:21 +0100118 last_timer = NULL;
119 return t;
120}
121
122static inline struct task *task_unlink_wq(struct task *t)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200123{
Willy Tarreau4726f532009-03-07 17:25:21 +0100124 if (likely(task_in_wq(t)))
125 __task_unlink_wq(t);
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200126 return t;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200127}
128
129/*
Willy Tarreau4726f532009-03-07 17:25:21 +0100130 * Unlink the task from the run queue. The run_queue size and number of niced
131 * tasks are updated too. A pointer to the task itself is returned. The task
132 * *must* already be in the wait queue before calling this function. If unsure,
133 * use the safer task_unlink_rq() function.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200134 */
Willy Tarreau4726f532009-03-07 17:25:21 +0100135static inline struct task *__task_unlink_rq(struct task *t)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200136{
Willy Tarreau4726f532009-03-07 17:25:21 +0100137 eb32_delete(&t->rq);
138 run_queue--;
139 if (likely(t->nice))
140 niced_tasks--;
Willy Tarreauce44f122008-07-05 18:16:19 +0200141 return t;
142}
Willy Tarreau9789f7b2008-06-24 08:17:16 +0200143
Willy Tarreau4726f532009-03-07 17:25:21 +0100144static inline struct task *task_unlink_rq(struct task *t)
145{
146 if (likely(task_in_rq(t)))
147 __task_unlink_rq(t);
148 return t;
149}
150
Willy Tarreauce44f122008-07-05 18:16:19 +0200151/*
152 * Unlinks the task and adjusts run queue stats.
153 * A pointer to the task itself is returned.
154 */
155static inline struct task *task_delete(struct task *t)
156{
Willy Tarreau4726f532009-03-07 17:25:21 +0100157 task_unlink_wq(t);
158 task_unlink_rq(t);
Willy Tarreau9789f7b2008-06-24 08:17:16 +0200159 return t;
160}
161
162/*
163 * Initialize a new task. The bare minimum is performed (queue pointers and state).
164 * The task is returned.
165 */
166static inline struct task *task_init(struct task *t)
167{
Willy Tarreau4726f532009-03-07 17:25:21 +0100168 t->wq.node.leaf_p = NULL;
169 t->rq.node.leaf_p = NULL;
Willy Tarreaufdccded2008-08-29 18:19:04 +0200170 t->state = TASK_SLEEPING;
Willy Tarreau91e99932008-06-30 07:51:00 +0200171 t->nice = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200172 return t;
173}
174
175/*
176 * frees a task. Its context must have been freed since it will be lost.
177 */
178static inline void task_free(struct task *t)
179{
Willy Tarreauc6ca1a02007-05-13 19:43:47 +0200180 pool_free2(pool2_task, t);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200181}
182
Willy Tarreau4726f532009-03-07 17:25:21 +0100183/* Place <task> into the wait queue, where it may already be. If the expiration
Willy Tarreau531cf0c2009-03-08 16:35:27 +0100184 * timer is infinite, do nothing and rely on wake_expired_task to clean up.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200185 */
Willy Tarreau531cf0c2009-03-08 16:35:27 +0100186void __task_queue(struct task *task);
187static inline void task_queue(struct task *task)
188{
189 /* If we already have a place in the wait queue no later than the
190 * timeout we're trying to set, we'll stay there, because it is very
191 * unlikely that we will reach the timeout anyway. If the timeout
192 * has been disabled, it's useless to leave the queue as well. We'll
193 * rely on wake_expired_tasks() to catch the node and move it to the
194 * proper place should it ever happen. Finally we only add the task
195 * to the queue if it was not there or if it was further than what
196 * we want.
197 */
198 if (!tick_isset(task->expire))
199 return;
200
Willy Tarreaue35c94a2009-03-21 10:01:42 +0100201 if (!task_in_wq(task) || tick_is_lt(task->expire, task->wq.key))
Willy Tarreau531cf0c2009-03-08 16:35:27 +0100202 __task_queue(task);
203}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200204
205/*
206 * This does 4 things :
207 * - wake up all expired tasks
208 * - call all runnable tasks
209 * - call maintain_proxies() to enable/disable the listeners
Willy Tarreaud825eef2007-05-12 22:35:00 +0200210 * - return the date of next event in <next> or eternity.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200211 */
212
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200213void process_runnable_tasks(int *next);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200214
Willy Tarreau58b458d2008-06-29 22:40:23 +0200215/*
216 * Extract all expired timers from the timer queue, and wakes up all
217 * associated tasks. Returns the date of next event (or eternity).
218 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200219void wake_expired_tasks(int *next);
Willy Tarreau58b458d2008-06-29 22:40:23 +0200220
Willy Tarreaud0a201b2009-03-08 15:53:06 +0100221/* Perform minimal initializations, report 0 in case of error, 1 if OK. */
222int init_task();
Willy Tarreaubaaee002006-06-26 02:48:02 +0200223
224#endif /* _PROTO_TASK_H */
225
226/*
227 * Local variables:
228 * c-indent-level: 8
229 * c-basic-offset: 8
230 * End:
231 */