blob: 6190670943b4ef1f8dc12f2173cdc89988c9aa6b [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 Tarreau12090332007-05-14 02:11:39 +020091#ifdef WAKE_HINT_CHECK_FIRST
Willy Tarreau96bcfd72007-04-29 10:41:56 +020092 /*
93 * Hint: tasks are *rarely* expired. So we can try to optimize
Willy Tarreau12090332007-05-14 02:11:39 +020094 * by not scanning the tree at all in most cases. However, this
95 * code costs 160 more bytes which do not look much useful because
96 * the performance win is not obvious.
Willy Tarreau96bcfd72007-04-29 10:41:56 +020097 */
98
99 if (likely(timer_wq.data != NULL)) {
100 task = LIST_ELEM(timer_wq.data, struct task *, qlist);
Willy Tarreauc64e5392007-05-13 16:07:06 +0200101 if (likely(tv_isgt(&task->expire, &now))) {
Willy Tarreaufbfc0532007-05-14 02:03:47 +0200102 *next = task->expire;
Willy Tarreauc64e5392007-05-13 16:07:06 +0200103 return;
Willy Tarreau7317eb52007-05-09 00:54:10 +0200104 }
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200105 }
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200106 /* OK we lose. Let's scan the tree then. */
Willy Tarreau12090332007-05-14 02:11:39 +0200107#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +0200108
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200109 tree64_foreach(&timer_wq, data, stack, slen) {
110 task = LIST_ELEM(data, struct task *, qlist);
111
Willy Tarreauc64e5392007-05-13 16:07:06 +0200112 if (tv_isgt(&task->expire, &now)) {
Willy Tarreaufbfc0532007-05-14 02:03:47 +0200113 *next = task->expire;
Willy Tarreau12090332007-05-14 02:11:39 +0200114 return;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200115 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200116
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200117 /*
118 * OK, all tasks linked to this node will be unlinked, as well
119 * as the node itself, so we do not need to care about correct
120 * unlinking.
121 */
122 foreach_dlist_item(task, data, struct task *, qlist) {
123 DLIST_DEL(&task->qlist);
124 task->wq = NULL;
125 DLIST_ADD(run_queue, &task->qlist);
126 task->state = TASK_RUNNING;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200127 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200128 }
Willy Tarreau12090332007-05-14 02:11:39 +0200129 tv_eternity(next);
Willy Tarreaud825eef2007-05-12 22:35:00 +0200130 return;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200131}
132
133/*
134 * This does 4 things :
135 * - wake up all expired tasks
136 * - call all runnable tasks
137 * - call maintain_proxies() to enable/disable the listeners
Willy Tarreaud825eef2007-05-12 22:35:00 +0200138 * - return the date of next event in <next> or eternity.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200139 *
140 */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200141void process_runnable_tasks(struct timeval *next)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200142{
Willy Tarreaud825eef2007-05-12 22:35:00 +0200143 struct timeval temp;
Willy Tarreau964c9362007-01-07 00:38:00 +0100144 struct task *t;
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200145 void *queue;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200146
Willy Tarreaud825eef2007-05-12 22:35:00 +0200147 wake_expired_tasks(next);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200148 /* process each task in the run queue now. Each task may be deleted
149 * since we only use the run queue's head. Note that any task can be
150 * woken up by any other task and it will be processed immediately
Willy Tarreau964c9362007-01-07 00:38:00 +0100151 * after as it will be queued on the run queue's head !
Willy Tarreaubaaee002006-06-26 02:48:02 +0200152 */
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200153
154 queue = run_queue;
155 foreach_dlist_item(t, queue, struct task *, qlist) {
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200156 DLIST_DEL(&t->qlist);
157 t->qlist.p = NULL;
158
159 t->state = TASK_IDLE;
Willy Tarreaud825eef2007-05-12 22:35:00 +0200160 t->process(t, &temp);
161 tv_bound(next, &temp);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200162 }
Willy Tarreau964c9362007-01-07 00:38:00 +0100163
164 /* maintain all proxies in a consistent state. This should quickly
165 * become a task because it becomes expensive when there are huge
166 * numbers of proxies. */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200167 maintain_proxies(&temp);
168 tv_bound(next, &temp);
169 return;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200170}
171
Willy Tarreaubaaee002006-06-26 02:48:02 +0200172/*
173 * Local variables:
174 * c-indent-level: 8
175 * c-basic-offset: 8
176 * End:
177 */