| /* |
| * Task management functions. |
| * |
| * Copyright 2000-2006 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 |
| * as published by the Free Software Foundation; either version |
| * 2 of the License, or (at your option) any later version. |
| * |
| */ |
| |
| #include <common/config.h> |
| #include <common/mini-clist.h> |
| #include <common/time.h> |
| |
| #include <proto/task.h> |
| |
| |
| /* FIXME : this should be removed very quickly ! */ |
| extern int maintain_proxies(void); |
| |
| void **pool_task= NULL; |
| struct task *rq = NULL; /* global run queue */ |
| |
| struct rb_root wait_queue[2] = { |
| RB_ROOT, |
| RB_ROOT, |
| }; |
| |
| |
| static inline void __rb_insert_task_queue(struct task *newtask) |
| { |
| struct rb_node **p = &newtask->wq->rb_node; |
| struct rb_node *parent = NULL; |
| struct task * task; |
| |
| while (*p) |
| { |
| parent = *p; |
| task = rb_entry(parent, struct task, rb_node); |
| if (tv_cmp_ge2(&task->expire, &newtask->expire)) |
| p = &(*p)->rb_left; |
| else |
| p = &(*p)->rb_right; |
| } |
| rb_link_node(&newtask->rb_node, parent, p); |
| } |
| |
| static void rb_insert_task_queue(struct task *newtask) |
| { |
| __rb_insert_task_queue(newtask); |
| rb_insert_color(&newtask->rb_node, newtask->wq); |
| } |
| |
| |
| struct task *task_queue(struct task *task) |
| { |
| struct rb_node *node; |
| struct task *next, *prev; |
| |
| if (tv_iseternity(&task->expire)) { |
| if (task->wq) { |
| if (task->wq == &wait_queue[1]) |
| return task; |
| else |
| task_delete(task); |
| } |
| task->wq = &wait_queue[1]; |
| rb_insert_task_queue(task); |
| return task; |
| } else { |
| if (task->wq != &wait_queue[0]) { |
| if (task->wq) |
| task_delete(task); |
| task->wq = &wait_queue[0]; |
| rb_insert_task_queue(task); |
| return task; |
| } |
| |
| // check whether task should be re insert |
| node = rb_prev(&task->rb_node); |
| if (node) { |
| prev = rb_entry(node, struct task, rb_node); |
| if (tv_cmp_ge(&prev->expire, &task->expire)) { |
| task_delete(task); |
| task->wq = &wait_queue[0]; |
| rb_insert_task_queue(task); |
| return task; |
| } |
| } |
| |
| node = rb_next(&task->rb_node); |
| if (node) { |
| next = rb_entry(node, struct task, rb_node); |
| if (tv_cmp_ge(&task->expire, &next->expire)) { |
| task_delete(task); |
| task->wq = &wait_queue[0]; |
| rb_insert_task_queue(task); |
| return task; |
| } |
| } |
| return task; |
| } |
| } |
| |
| /* |
| * This does 4 things : |
| * - 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 |
| * |
| */ |
| int process_runnable_tasks() |
| { |
| int next_time; |
| int time2; |
| struct task *t; |
| struct rb_node *node; |
| |
| next_time = TIME_ETERNITY; |
| for (node = rb_first(&wait_queue[0]); |
| node != NULL; node = rb_next(node)) { |
| t = rb_entry(node, struct task, rb_node); |
| if (t->state & TASK_RUNNING) |
| continue; |
| if (tv_iseternity(&t->expire)) |
| continue; |
| if (tv_cmp_ms(&t->expire, &now) <= 0) { |
| task_wakeup(&rq, t); |
| } else { |
| int temp_time = tv_remain(&now, &t->expire); |
| if (temp_time) |
| next_time = temp_time; |
| break; |
| } |
| } |
| |
| /* 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 |
| * after as it will be queued on the run queue's head ! |
| */ |
| while ((t = rq) != NULL) { |
| int temp_time; |
| |
| task_sleep(&rq, t); |
| temp_time = t->process(t); |
| next_time = MINTIME(temp_time, next_time); |
| } |
| |
| /* 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); |
| } |
| |
| /* |
| * Local variables: |
| * c-indent-level: 8 |
| * c-basic-offset: 8 |
| * End: |
| */ |