blob: 182de2508c5cef43d4551415cbf57b8d13d1c9df [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>
Willy Tarreauc6ca1a02007-05-13 19:43:47 +020014#include <common/memory.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020015#include <common/mini-clist.h>
Willy Tarreau96bcfd72007-04-29 10:41:56 +020016#include <common/standard.h>
Willy Tarreaua6a6a932007-04-28 22:40:08 +020017#include <common/time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020018
Willy Tarreaud825eef2007-05-12 22:35:00 +020019#include <proto/proxy.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020020#include <proto/task.h>
Willy Tarreau96bcfd72007-04-29 10:41:56 +020021#include <types/task.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020022
Willy Tarreau96bcfd72007-04-29 10:41:56 +020023// FIXME: check 8bitops.c for faster FLS
24#include <import/bitops.h>
25#include <import/tree.h>
26
Willy Tarreau96bcfd72007-04-29 10:41:56 +020027static struct ultree *stack[LLONGBITS];
Willy Tarreau964c9362007-01-07 00:38:00 +010028
Willy Tarreauc6ca1a02007-05-13 19:43:47 +020029struct pool_head *pool2_task, *pool2_tree64;
30
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 Tarreauc6ca1a02007-05-13 19:43:47 +020035/* perform minimal intializations, report 0 in case of error, 1 if OK. */
36int init_task()
37{
38 pool2_task = create_pool("task", sizeof(struct task), MEM_F_SHARED);
39 pool2_tree64 = create_pool("tree64", sizeof(struct tree64), MEM_F_SHARED);
40 return pool2_task && pool2_tree64;
41}
42
Willy Tarreau96bcfd72007-04-29 10:41:56 +020043struct ultree *ul2tree_insert(struct ultree *root, unsigned long h, unsigned long l)
Willy Tarreau964c9362007-01-07 00:38:00 +010044{
Willy Tarreau96bcfd72007-04-29 10:41:56 +020045 return __ul2tree_insert(root, h, l);
46}
Willy Tarreau964c9362007-01-07 00:38:00 +010047
Willy Tarreau96bcfd72007-04-29 10:41:56 +020048void *tree_delete(void *node) {
49 return __tree_delete(node);
Willy Tarreau964c9362007-01-07 00:38:00 +010050}
51
Willy Tarreaue33aece2007-04-30 13:15:14 +020052struct task *_task_wakeup(struct task *t)
53{
54 return __task_wakeup(t);
55}
Willy Tarreaud825eef2007-05-12 22:35:00 +020056
Willy Tarreau96bcfd72007-04-29 10:41:56 +020057/*
58 * task_queue()
59 *
60 * Inserts a task into the wait queue at the position given by its expiration
61 * date.
62 *
63 */
64struct task *task_queue(struct task *task)
Willy Tarreau964c9362007-01-07 00:38:00 +010065{
Willy Tarreau96bcfd72007-04-29 10:41:56 +020066 if (unlikely(task->qlist.p != NULL)) {
67 DLIST_DEL(&task->qlist);
68 task->qlist.p = NULL;
69 }
70
71 if (unlikely(task->wq)) {
72 tree_delete(task->wq);
73 task->wq = NULL;
74 }
75
76 if (unlikely(tv_iseternity(&task->expire))) {
77 task->wq = NULL;
78 DLIST_ADD(eternity_queue, &task->qlist);
79 return task;
80 }
81
82 task->wq = ul2tree_insert(&timer_wq, task->expire.tv_sec, task->expire.tv_usec);
83 DLIST_ADD(task->wq->data, &task->qlist);
84 return task;
Willy Tarreau964c9362007-01-07 00:38:00 +010085}
86
87
Willy Tarreau96bcfd72007-04-29 10:41:56 +020088/*
89 * Extract all expired timers from the wait queue, and wakes up all
Willy Tarreaud825eef2007-05-12 22:35:00 +020090 * associated tasks. Returns the date of next event (or eternity).
Willy Tarreau96bcfd72007-04-29 10:41:56 +020091 *
92 */
Willy Tarreaud825eef2007-05-12 22:35:00 +020093void wake_expired_tasks(struct timeval *next)
Willy Tarreaubaaee002006-06-26 02:48:02 +020094{
Willy Tarreau96bcfd72007-04-29 10:41:56 +020095 int slen;
96 struct task *task;
97 void *data;
Willy Tarreaubaaee002006-06-26 02:48:02 +020098
Willy Tarreau96bcfd72007-04-29 10:41:56 +020099 /*
100 * Hint: tasks are *rarely* expired. So we can try to optimize
101 * by not scanning the tree at all in most cases.
102 */
103
104 if (likely(timer_wq.data != NULL)) {
105 task = LIST_ELEM(timer_wq.data, struct task *, qlist);
Willy Tarreauc64e5392007-05-13 16:07:06 +0200106 if (likely(tv_isgt(&task->expire, &now))) {
107 tv_remain(&now, &task->expire, next);
108 return;
Willy Tarreau7317eb52007-05-09 00:54:10 +0200109 }
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200110 }
111
112 /* OK we lose. Let's scan the tree then. */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200113 tv_eternity(next);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200114
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200115 tree64_foreach(&timer_wq, data, stack, slen) {
116 task = LIST_ELEM(data, struct task *, qlist);
117
Willy Tarreauc64e5392007-05-13 16:07:06 +0200118 if (tv_isgt(&task->expire, &now)) {
119 tv_remain(&now, &task->expire, next);
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200120 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200121 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200122
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200123 /*
124 * OK, all tasks linked to this node will be unlinked, as well
125 * as the node itself, so we do not need to care about correct
126 * unlinking.
127 */
128 foreach_dlist_item(task, data, struct task *, qlist) {
129 DLIST_DEL(&task->qlist);
130 task->wq = NULL;
131 DLIST_ADD(run_queue, &task->qlist);
132 task->state = TASK_RUNNING;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200133 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200134 }
Willy Tarreaud825eef2007-05-12 22:35:00 +0200135 return;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200136}
137
138/*
139 * This does 4 things :
140 * - wake up all expired tasks
141 * - call all runnable tasks
142 * - call maintain_proxies() to enable/disable the listeners
Willy Tarreaud825eef2007-05-12 22:35:00 +0200143 * - return the date of next event in <next> or eternity.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200144 *
145 */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200146void process_runnable_tasks(struct timeval *next)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200147{
Willy Tarreaud825eef2007-05-12 22:35:00 +0200148 struct timeval temp;
Willy Tarreau964c9362007-01-07 00:38:00 +0100149 struct task *t;
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200150 void *queue;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200151
Willy Tarreaud825eef2007-05-12 22:35:00 +0200152 wake_expired_tasks(next);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200153 /* process each task in the run queue now. Each task may be deleted
154 * since we only use the run queue's head. Note that any task can be
155 * woken up by any other task and it will be processed immediately
Willy Tarreau964c9362007-01-07 00:38:00 +0100156 * after as it will be queued on the run queue's head !
Willy Tarreaubaaee002006-06-26 02:48:02 +0200157 */
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200158
159 queue = run_queue;
160 foreach_dlist_item(t, queue, struct task *, qlist) {
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200161 DLIST_DEL(&t->qlist);
162 t->qlist.p = NULL;
163
164 t->state = TASK_IDLE;
Willy Tarreaud825eef2007-05-12 22:35:00 +0200165 t->process(t, &temp);
166 tv_bound(next, &temp);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200167 }
Willy Tarreau964c9362007-01-07 00:38:00 +0100168
169 /* maintain all proxies in a consistent state. This should quickly
170 * become a task because it becomes expensive when there are huge
171 * numbers of proxies. */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200172 maintain_proxies(&temp);
173 tv_bound(next, &temp);
174 return;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200175}
176
Willy Tarreaubaaee002006-06-26 02:48:02 +0200177/*
178 * Local variables:
179 * c-indent-level: 8
180 * c-basic-offset: 8
181 * End:
182 */