blob: 953da6c7c5b76be03846c3cceba17b1d1f0946f8 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * Task management functions.
3 *
Willy Tarreau96bcfd72007-04-29 10:41:56 +02004 * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
Willy Tarreaubaaee002006-06-26 02:48:02 +02005 *
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>
Willy Tarreau96bcfd72007-04-29 10:41:56 +020015#include <common/standard.h>
Willy Tarreaua6a6a932007-04-28 22:40:08 +020016#include <common/time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020017
Willy Tarreaud825eef2007-05-12 22:35:00 +020018#include <proto/proxy.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020019#include <proto/task.h>
Willy Tarreau96bcfd72007-04-29 10:41:56 +020020#include <types/task.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020021
Willy Tarreau96bcfd72007-04-29 10:41:56 +020022// FIXME: check 8bitops.c for faster FLS
23#include <import/bitops.h>
24#include <import/tree.h>
25
Willy Tarreaubaaee002006-06-26 02:48:02 +020026
Willy Tarreaubaaee002006-06-26 02:48:02 +020027void **pool_task= NULL;
Willy Tarreau96bcfd72007-04-29 10:41:56 +020028void **pool_tree64 = NULL;
29static struct ultree *stack[LLONGBITS];
Willy Tarreau964c9362007-01-07 00:38:00 +010030
Willy Tarreau96bcfd72007-04-29 10:41:56 +020031UL2TREE_HEAD(timer_wq);
32void *eternity_queue = NULL;
33void *run_queue = NULL;
Willy Tarreaubaaee002006-06-26 02:48:02 +020034
Willy Tarreau96bcfd72007-04-29 10:41:56 +020035struct ultree *ul2tree_insert(struct ultree *root, unsigned long h, unsigned long l)
Willy Tarreau964c9362007-01-07 00:38:00 +010036{
Willy Tarreau96bcfd72007-04-29 10:41:56 +020037 return __ul2tree_insert(root, h, l);
38}
Willy Tarreau964c9362007-01-07 00:38:00 +010039
Willy Tarreau96bcfd72007-04-29 10:41:56 +020040void *tree_delete(void *node) {
41 return __tree_delete(node);
Willy Tarreau964c9362007-01-07 00:38:00 +010042}
43
Willy Tarreaue33aece2007-04-30 13:15:14 +020044struct task *_task_wakeup(struct task *t)
45{
46 return __task_wakeup(t);
47}
Willy Tarreaud825eef2007-05-12 22:35:00 +020048
Willy Tarreau96bcfd72007-04-29 10:41:56 +020049/*
50 * task_queue()
51 *
52 * Inserts a task into the wait queue at the position given by its expiration
53 * date.
54 *
55 */
56struct task *task_queue(struct task *task)
Willy Tarreau964c9362007-01-07 00:38:00 +010057{
Willy Tarreau96bcfd72007-04-29 10:41:56 +020058 if (unlikely(task->qlist.p != NULL)) {
59 DLIST_DEL(&task->qlist);
60 task->qlist.p = NULL;
61 }
62
63 if (unlikely(task->wq)) {
64 tree_delete(task->wq);
65 task->wq = NULL;
66 }
67
68 if (unlikely(tv_iseternity(&task->expire))) {
69 task->wq = NULL;
70 DLIST_ADD(eternity_queue, &task->qlist);
71 return task;
72 }
73
74 task->wq = ul2tree_insert(&timer_wq, task->expire.tv_sec, task->expire.tv_usec);
75 DLIST_ADD(task->wq->data, &task->qlist);
76 return task;
Willy Tarreau964c9362007-01-07 00:38:00 +010077}
78
79
Willy Tarreau96bcfd72007-04-29 10:41:56 +020080/*
81 * Extract all expired timers from the wait queue, and wakes up all
Willy Tarreaud825eef2007-05-12 22:35:00 +020082 * associated tasks. Returns the date of next event (or eternity).
Willy Tarreau96bcfd72007-04-29 10:41:56 +020083 *
84 */
Willy Tarreaud825eef2007-05-12 22:35:00 +020085void wake_expired_tasks(struct timeval *next)
Willy Tarreaubaaee002006-06-26 02:48:02 +020086{
Willy Tarreau7317eb52007-05-09 00:54:10 +020087 __label__ out;
Willy Tarreau96bcfd72007-04-29 10:41:56 +020088 int slen;
89 struct task *task;
90 void *data;
Willy Tarreaubaaee002006-06-26 02:48:02 +020091
Willy Tarreau96bcfd72007-04-29 10:41:56 +020092 /*
93 * Hint: tasks are *rarely* expired. So we can try to optimize
94 * by not scanning the tree at all in most cases.
95 */
96
97 if (likely(timer_wq.data != NULL)) {
98 task = LIST_ELEM(timer_wq.data, struct task *, qlist);
Willy Tarreau7317eb52007-05-09 00:54:10 +020099 if (likely(__tv_isge(&task->expire, &now) > 0)) {
Willy Tarreaud825eef2007-05-12 22:35:00 +0200100 __tv_remain(&now, &task->expire, next);
Willy Tarreau7317eb52007-05-09 00:54:10 +0200101 goto out;
102 }
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200103 }
104
105 /* OK we lose. Let's scan the tree then. */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200106 tv_eternity(next);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200107
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200108 tree64_foreach(&timer_wq, data, stack, slen) {
109 task = LIST_ELEM(data, struct task *, qlist);
110
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200111 if (__tv_isgt(&task->expire, &now)) {
Willy Tarreaud825eef2007-05-12 22:35:00 +0200112 __tv_remain2(&now, &task->expire, next);
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200113 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200114 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200115
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200116 /*
117 * OK, all tasks linked to this node will be unlinked, as well
118 * as the node itself, so we do not need to care about correct
119 * unlinking.
120 */
121 foreach_dlist_item(task, data, struct task *, qlist) {
122 DLIST_DEL(&task->qlist);
123 task->wq = NULL;
124 DLIST_ADD(run_queue, &task->qlist);
125 task->state = TASK_RUNNING;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200126 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200127 }
Willy Tarreau7317eb52007-05-09 00:54:10 +0200128 out:
Willy Tarreaud825eef2007-05-12 22:35:00 +0200129 return;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200130}
131
132/*
133 * This does 4 things :
134 * - wake up all expired tasks
135 * - call all runnable tasks
136 * - call maintain_proxies() to enable/disable the listeners
Willy Tarreaud825eef2007-05-12 22:35:00 +0200137 * - return the date of next event in <next> or eternity.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200138 *
139 */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200140void process_runnable_tasks(struct timeval *next)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200141{
Willy Tarreaud825eef2007-05-12 22:35:00 +0200142 struct timeval temp;
Willy Tarreau964c9362007-01-07 00:38:00 +0100143 struct task *t;
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200144 void *queue;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200145
Willy Tarreaud825eef2007-05-12 22:35:00 +0200146 wake_expired_tasks(next);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200147 /* process each task in the run queue now. Each task may be deleted
148 * since we only use the run queue's head. Note that any task can be
149 * woken up by any other task and it will be processed immediately
Willy Tarreau964c9362007-01-07 00:38:00 +0100150 * after as it will be queued on the run queue's head !
Willy Tarreaubaaee002006-06-26 02:48:02 +0200151 */
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200152
153 queue = run_queue;
154 foreach_dlist_item(t, queue, struct task *, qlist) {
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200155 DLIST_DEL(&t->qlist);
156 t->qlist.p = NULL;
157
158 t->state = TASK_IDLE;
Willy Tarreaud825eef2007-05-12 22:35:00 +0200159 t->process(t, &temp);
160 tv_bound(next, &temp);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200161 }
Willy Tarreau964c9362007-01-07 00:38:00 +0100162
163 /* maintain all proxies in a consistent state. This should quickly
164 * become a task because it becomes expensive when there are huge
165 * numbers of proxies. */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200166 maintain_proxies(&temp);
167 tv_bound(next, &temp);
168 return;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200169}
170
Willy Tarreaubaaee002006-06-26 02:48:02 +0200171/*
172 * Local variables:
173 * c-indent-level: 8
174 * c-basic-offset: 8
175 * End:
176 */