blob: 41c0b2a2b3a5f2dd2d89b42cb306b1d16055fe85 [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 Tarreau96bcfd72007-04-29 10:41:56 +020087 int slen;
88 struct task *task;
89 void *data;
Willy Tarreaubaaee002006-06-26 02:48:02 +020090
Willy Tarreau96bcfd72007-04-29 10:41:56 +020091 /*
92 * Hint: tasks are *rarely* expired. So we can try to optimize
93 * by not scanning the tree at all in most cases.
94 */
95
96 if (likely(timer_wq.data != NULL)) {
97 task = LIST_ELEM(timer_wq.data, struct task *, qlist);
Willy Tarreauc64e5392007-05-13 16:07:06 +020098 if (likely(tv_isgt(&task->expire, &now))) {
99 tv_remain(&now, &task->expire, next);
100 return;
Willy Tarreau7317eb52007-05-09 00:54:10 +0200101 }
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200102 }
103
104 /* OK we lose. Let's scan the tree then. */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200105 tv_eternity(next);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200106
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200107 tree64_foreach(&timer_wq, data, stack, slen) {
108 task = LIST_ELEM(data, struct task *, qlist);
109
Willy Tarreauc64e5392007-05-13 16:07:06 +0200110 if (tv_isgt(&task->expire, &now)) {
111 tv_remain(&now, &task->expire, next);
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200112 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200113 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200114
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200115 /*
116 * OK, all tasks linked to this node will be unlinked, as well
117 * as the node itself, so we do not need to care about correct
118 * unlinking.
119 */
120 foreach_dlist_item(task, data, struct task *, qlist) {
121 DLIST_DEL(&task->qlist);
122 task->wq = NULL;
123 DLIST_ADD(run_queue, &task->qlist);
124 task->state = TASK_RUNNING;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200125 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200126 }
Willy Tarreaud825eef2007-05-12 22:35:00 +0200127 return;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200128}
129
130/*
131 * This does 4 things :
132 * - wake up all expired tasks
133 * - call all runnable tasks
134 * - call maintain_proxies() to enable/disable the listeners
Willy Tarreaud825eef2007-05-12 22:35:00 +0200135 * - return the date of next event in <next> or eternity.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200136 *
137 */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200138void process_runnable_tasks(struct timeval *next)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200139{
Willy Tarreaud825eef2007-05-12 22:35:00 +0200140 struct timeval temp;
Willy Tarreau964c9362007-01-07 00:38:00 +0100141 struct task *t;
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200142 void *queue;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200143
Willy Tarreaud825eef2007-05-12 22:35:00 +0200144 wake_expired_tasks(next);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200145 /* process each task in the run queue now. Each task may be deleted
146 * since we only use the run queue's head. Note that any task can be
147 * woken up by any other task and it will be processed immediately
Willy Tarreau964c9362007-01-07 00:38:00 +0100148 * after as it will be queued on the run queue's head !
Willy Tarreaubaaee002006-06-26 02:48:02 +0200149 */
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200150
151 queue = run_queue;
152 foreach_dlist_item(t, queue, struct task *, qlist) {
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200153 DLIST_DEL(&t->qlist);
154 t->qlist.p = NULL;
155
156 t->state = TASK_IDLE;
Willy Tarreaud825eef2007-05-12 22:35:00 +0200157 t->process(t, &temp);
158 tv_bound(next, &temp);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200159 }
Willy Tarreau964c9362007-01-07 00:38:00 +0100160
161 /* maintain all proxies in a consistent state. This should quickly
162 * become a task because it becomes expensive when there are huge
163 * numbers of proxies. */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200164 maintain_proxies(&temp);
165 tv_bound(next, &temp);
166 return;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200167}
168
Willy Tarreaubaaee002006-06-26 02:48:02 +0200169/*
170 * Local variables:
171 * c-indent-level: 8
172 * c-basic-offset: 8
173 * End:
174 */