blob: beddb27e3d98e644f0277c41063e49aa0061e688 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * Task management functions.
3 *
4 * Copyright 2000-2006 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
Willy Tarreau2dd0d472006-06-29 17:53:05 +020013#include <common/config.h>
14#include <common/mini-clist.h>
15#include <common/time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020016
17#include <proto/task.h>
18
19
20/* FIXME : this should be removed very quickly ! */
21extern int maintain_proxies(void);
22
23void **pool_task= NULL;
24struct task *rq = NULL; /* global run queue */
Willy Tarreau964c9362007-01-07 00:38:00 +010025
26struct rb_root wait_queue[2] = {
27 RB_ROOT,
28 RB_ROOT,
Willy Tarreaubaaee002006-06-26 02:48:02 +020029};
30
31
Willy Tarreau964c9362007-01-07 00:38:00 +010032static inline void __rb_insert_task_queue(struct task *newtask)
33{
34 struct rb_node **p = &newtask->wq->rb_node;
35 struct rb_node *parent = NULL;
36 struct task * task;
37
38 while (*p)
39 {
40 parent = *p;
41 task = rb_entry(parent, struct task, rb_node);
42 if (tv_cmp2(&task->expire, &newtask->expire) >= 0)
43 p = &(*p)->rb_left;
44 else
45 p = &(*p)->rb_right;
46 }
47 rb_link_node(&newtask->rb_node, parent, p);
48}
49
50static inline void rb_insert_task_queue(struct task *newtask)
51{
52 __rb_insert_task_queue(newtask);
53 rb_insert_color(&newtask->rb_node, newtask->wq);
54}
55
56
Willy Tarreaubaaee002006-06-26 02:48:02 +020057struct task *task_queue(struct task *task)
58{
Willy Tarreau964c9362007-01-07 00:38:00 +010059 struct rb_node *node;
60 struct task *next, *prev;
Willy Tarreaubaaee002006-06-26 02:48:02 +020061
Willy Tarreaubaaee002006-06-26 02:48:02 +020062 if (tv_iseternity(&task->expire)) {
Willy Tarreau964c9362007-01-07 00:38:00 +010063 if (task->wq) {
64 if (task->wq == &wait_queue[1])
Willy Tarreaubaaee002006-06-26 02:48:02 +020065 return task;
Willy Tarreau964c9362007-01-07 00:38:00 +010066 else
Willy Tarreaubaaee002006-06-26 02:48:02 +020067 task_delete(task);
Willy Tarreaubaaee002006-06-26 02:48:02 +020068 }
Willy Tarreau964c9362007-01-07 00:38:00 +010069 task->wq = &wait_queue[1];
70 rb_insert_task_queue(task);
71 return task;
Willy Tarreaubaaee002006-06-26 02:48:02 +020072 } else {
Willy Tarreau964c9362007-01-07 00:38:00 +010073 if (task->wq != &wait_queue[0]) {
74 if (task->wq)
75 task_delete(task);
76 task->wq = &wait_queue[0];
77 rb_insert_task_queue(task);
78 return task;
Willy Tarreaubaaee002006-06-26 02:48:02 +020079 }
80
Willy Tarreau964c9362007-01-07 00:38:00 +010081 // check whether task should be re insert
82 node = rb_prev(&task->rb_node);
83 if (node) {
84 prev = rb_entry(node, struct task, rb_node);
85 if (tv_cmp2(&prev->expire, &task->expire) >= 0) {
86 task_delete(task);
87 task->wq = &wait_queue[0];
88 rb_insert_task_queue(task);
89 return task;
90 }
Willy Tarreaubaaee002006-06-26 02:48:02 +020091 }
Willy Tarreaubaaee002006-06-26 02:48:02 +020092
Willy Tarreau964c9362007-01-07 00:38:00 +010093 node = rb_next(&task->rb_node);
94 if (node) {
95 next = rb_entry(node, struct task, rb_node);
96 if (tv_cmp2(&task->expire, &next->expire) > 0) {
97 task_delete(task);
98 task->wq = &wait_queue[0];
99 rb_insert_task_queue(task);
100 return task;
101 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200102 }
Willy Tarreau964c9362007-01-07 00:38:00 +0100103 return task;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200104 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200105}
106
107/*
108 * This does 4 things :
109 * - wake up all expired tasks
110 * - call all runnable tasks
111 * - call maintain_proxies() to enable/disable the listeners
112 * - return the delay till next event in ms, -1 = wait indefinitely
Willy Tarreaubaaee002006-06-26 02:48:02 +0200113 *
114 */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200115int process_runnable_tasks()
116{
117 int next_time;
118 int time2;
Willy Tarreau964c9362007-01-07 00:38:00 +0100119 struct task *t;
120 struct rb_node *node;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200121
Willy Tarreau964c9362007-01-07 00:38:00 +0100122 next_time = TIME_ETERNITY;
123 for (node = rb_first(&wait_queue[0]);
124 node != NULL; node = rb_next(node)) {
125 t = rb_entry(node, struct task, rb_node);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200126 if (t->state & TASK_RUNNING)
127 continue;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200128 if (tv_iseternity(&t->expire))
129 continue;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200130 if (tv_cmp_ms(&t->expire, &now) <= 0) {
131 task_wakeup(&rq, t);
Willy Tarreau964c9362007-01-07 00:38:00 +0100132 } else {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200133 int temp_time = tv_remain(&now, &t->expire);
134 if (temp_time)
135 next_time = temp_time;
136 break;
137 }
138 }
139
140 /* process each task in the run queue now. Each task may be deleted
141 * since we only use the run queue's head. Note that any task can be
142 * woken up by any other task and it will be processed immediately
Willy Tarreau964c9362007-01-07 00:38:00 +0100143 * after as it will be queued on the run queue's head !
Willy Tarreaubaaee002006-06-26 02:48:02 +0200144 */
145 while ((t = rq) != NULL) {
146 int temp_time;
147
148 task_sleep(&rq, t);
149 temp_time = t->process(t);
150 next_time = MINTIME(temp_time, next_time);
151 }
Willy Tarreau964c9362007-01-07 00:38:00 +0100152
153 /* maintain all proxies in a consistent state. This should quickly
154 * become a task because it becomes expensive when there are huge
155 * numbers of proxies. */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200156 time2 = maintain_proxies();
157 return MINTIME(time2, next_time);
158}
159
Willy Tarreaubaaee002006-06-26 02:48:02 +0200160/*
161 * Local variables:
162 * c-indent-level: 8
163 * c-basic-offset: 8
164 * End:
165 */