blob: 7f6e0e7a2359c4b26821c530e4e22fab5b35fe30 [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 Tarreau12090332007-05-14 02:11:39 +020099#ifdef WAKE_HINT_CHECK_FIRST
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200100 /*
101 * Hint: tasks are *rarely* expired. So we can try to optimize
Willy Tarreau12090332007-05-14 02:11:39 +0200102 * by not scanning the tree at all in most cases. However, this
103 * code costs 160 more bytes which do not look much useful because
104 * the performance win is not obvious.
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200105 */
106
107 if (likely(timer_wq.data != NULL)) {
108 task = LIST_ELEM(timer_wq.data, struct task *, qlist);
Willy Tarreauc64e5392007-05-13 16:07:06 +0200109 if (likely(tv_isgt(&task->expire, &now))) {
Willy Tarreaufbfc0532007-05-14 02:03:47 +0200110 *next = task->expire;
Willy Tarreauc64e5392007-05-13 16:07:06 +0200111 return;
Willy Tarreau7317eb52007-05-09 00:54:10 +0200112 }
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200113 }
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200114 /* OK we lose. Let's scan the tree then. */
Willy Tarreau12090332007-05-14 02:11:39 +0200115#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +0200116
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200117 tree64_foreach(&timer_wq, data, stack, slen) {
118 task = LIST_ELEM(data, struct task *, qlist);
119
Willy Tarreauc64e5392007-05-13 16:07:06 +0200120 if (tv_isgt(&task->expire, &now)) {
Willy Tarreaufbfc0532007-05-14 02:03:47 +0200121 *next = task->expire;
Willy Tarreau12090332007-05-14 02:11:39 +0200122 return;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200123 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200124
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200125 /*
126 * OK, all tasks linked to this node will be unlinked, as well
127 * as the node itself, so we do not need to care about correct
128 * unlinking.
129 */
130 foreach_dlist_item(task, data, struct task *, qlist) {
131 DLIST_DEL(&task->qlist);
132 task->wq = NULL;
133 DLIST_ADD(run_queue, &task->qlist);
134 task->state = TASK_RUNNING;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200135 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200136 }
Willy Tarreau12090332007-05-14 02:11:39 +0200137 tv_eternity(next);
Willy Tarreaud825eef2007-05-12 22:35:00 +0200138 return;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200139}
140
141/*
142 * This does 4 things :
143 * - wake up all expired tasks
144 * - call all runnable tasks
145 * - call maintain_proxies() to enable/disable the listeners
Willy Tarreaud825eef2007-05-12 22:35:00 +0200146 * - return the date of next event in <next> or eternity.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200147 *
148 */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200149void process_runnable_tasks(struct timeval *next)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200150{
Willy Tarreaud825eef2007-05-12 22:35:00 +0200151 struct timeval temp;
Willy Tarreau964c9362007-01-07 00:38:00 +0100152 struct task *t;
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200153 void *queue;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200154
Willy Tarreaud825eef2007-05-12 22:35:00 +0200155 wake_expired_tasks(next);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200156 /* process each task in the run queue now. Each task may be deleted
157 * since we only use the run queue's head. Note that any task can be
158 * woken up by any other task and it will be processed immediately
Willy Tarreau964c9362007-01-07 00:38:00 +0100159 * after as it will be queued on the run queue's head !
Willy Tarreaubaaee002006-06-26 02:48:02 +0200160 */
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200161
162 queue = run_queue;
163 foreach_dlist_item(t, queue, struct task *, qlist) {
Willy Tarreau96bcfd72007-04-29 10:41:56 +0200164 DLIST_DEL(&t->qlist);
165 t->qlist.p = NULL;
166
167 t->state = TASK_IDLE;
Willy Tarreaud825eef2007-05-12 22:35:00 +0200168 t->process(t, &temp);
169 tv_bound(next, &temp);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200170 }
Willy Tarreau964c9362007-01-07 00:38:00 +0100171
172 /* maintain all proxies in a consistent state. This should quickly
173 * become a task because it becomes expensive when there are huge
174 * numbers of proxies. */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200175 maintain_proxies(&temp);
176 tv_bound(next, &temp);
177 return;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200178}
179
Willy Tarreaubaaee002006-06-26 02:48:02 +0200180/*
181 * Local variables:
182 * c-indent-level: 8
183 * c-basic-offset: 8
184 * End:
185 */