1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
|
/*
* BIRD Library -- Event Processing
*
* (c) 1999 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
/**
* DOC: Events
*
* Events are there to keep track of deferred execution.
* Since BIRD is single-threaded, it requires long lasting tasks to be split to smaller
* parts, so that no module can monopolize the CPU. To split such a task, just create
* an &event resource, point it to the function you want to have called and call ev_schedule()
* to ask the core to run the event when nothing more important requires attention.
*
* You can also define your own event lists (the &event_list structure), enqueue your
* events in them and explicitly ask to run them.
*/
#include "nest/bird.h"
#include "lib/event.h"
event_list global_event_list;
event_list global_work_list;
inline void
ev_postpone(event *e)
{
if (ev_active(e))
{
rem_node(&e->n);
e->n.next = NULL;
}
}
static void
ev_dump(struct dump_request *dreq, resource *r)
{
event *e = (event *) r;
RDUMP("(code %p, data %p, %s)\n",
e->hook,
e->data,
e->n.next ? "scheduled" : "inactive");
}
static struct resclass ev_class = {
"Event",
sizeof(event),
(void (*)(resource *)) ev_postpone,
ev_dump,
NULL,
NULL
};
/**
* ev_new - create a new event
* @p: resource pool
*
* This function creates a new event resource. To use it,
* you need to fill the structure fields and call ev_schedule().
*/
event *
ev_new(pool *p)
{
event *e = ralloc(p, &ev_class);
return e;
}
/**
* ev_run - run an event
* @e: an event
*
* This function explicitly runs the event @e (calls its hook
* function) and removes it from an event list if it's linked to any.
*
* From the hook function, you can call ev_enqueue() or ev_schedule()
* to re-add the event.
*/
inline void
ev_run(event *e)
{
ev_postpone(e);
e->hook(e->data);
}
/**
* ev_enqueue - enqueue an event
* @l: an event list
* @e: an event
*
* ev_enqueue() stores the event @e to the specified event
* list @l which can be run by calling ev_run_list().
*/
inline void
ev_enqueue(event_list *l, event *e)
{
ev_postpone(e);
add_tail(l, &e->n);
}
/**
* ev_schedule - schedule an event
* @e: an event
*
* This function schedules an event by enqueueing it to a system-wide
* event list which is run by the platform dependent code whenever
* appropriate.
*/
void
ev_schedule(event *e)
{
ev_enqueue(&global_event_list, e);
}
/**
* ev_schedule_work - schedule a work-event.
* @e: an event
*
* This function schedules an event by enqueueing it to a system-wide work-event
* list which is run by the platform dependent code whenever appropriate. This
* is designated for work-events instead of regular events. They are executed
* less often in order to not clog I/O loop.
*/
void
ev_schedule_work(event *e)
{
if (!ev_active(e))
add_tail(&global_work_list, &e->n);
}
void io_log_event(void *hook, void *data);
/**
* ev_run_list - run an event list
* @l: an event list
*
* This function calls ev_run() for all events enqueued in the list @l.
*/
int
ev_run_list(event_list *l)
{
node *n;
list tmp_list;
init_list(&tmp_list);
add_tail_list(&tmp_list, l);
init_list(l);
WALK_LIST_FIRST(n, tmp_list)
{
event *e = SKIP_BACK(event, n, n);
/* This is ugly hack, we want to log just events executed from the main I/O loop */
if ((l == &global_event_list) || (l == &global_work_list))
io_log_event(e->hook, e->data);
ev_run(e);
tmp_flush();
}
return !EMPTY_LIST(*l);
}
int
ev_run_list_limited(event_list *l, uint limit)
{
node *n;
list tmp_list;
init_list(&tmp_list);
add_tail_list(&tmp_list, l);
init_list(l);
WALK_LIST_FIRST(n, tmp_list)
{
event *e = SKIP_BACK(event, n, n);
if (!limit)
break;
/* This is ugly hack, we want to log just events executed from the main I/O loop */
if ((l == &global_event_list) || (l == &global_work_list))
io_log_event(e->hook, e->data);
ev_run(e);
tmp_flush();
limit--;
}
if (!EMPTY_LIST(tmp_list))
{
/* Attach new items after the unprocessed old items */
add_tail_list(&tmp_list, l);
init_list(l);
add_tail_list(l, &tmp_list);
}
return !EMPTY_LIST(*l);
}
|