event.c 2.94 KB
Newer Older
1 2 3 4 5 6 7 8
/*
 *	BIRD Library -- Event Processing
 *
 *	(c) 1999 Martin Mares <mj@ucw.cz>
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

9 10 11 12 13 14 15
/**
 * 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()
Martin Mareš's avatar
Martin Mareš committed
16
 * to ask the core to run the event when nothing more important requires attention.
17 18 19 20 21
 *
 * You can also define your own event lists (the &event_list structure), enqueue your
 * events in them and explicitly ask to run them.
 */

22 23 24 25 26 27 28 29
#include "nest/bird.h"
#include "lib/event.h"

event_list global_event_list;

inline void
ev_postpone(event *e)
{
30
  if (ev_active(e))
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
    {
      rem_node(&e->n);
      e->n.next = NULL;
    }
}

static void
ev_dump(resource *r)
{
  event *e = (event *) r;

  debug("(code %p, data %p, %s)\n",
	e->hook,
	e->data,
	e->n.next ? "scheduled" : "inactive");
}

static struct resclass ev_class = {
  "Event",
50
  sizeof(event),
51
  (void (*)(resource *)) ev_postpone,
52
  ev_dump,
53
  NULL,
54
  NULL
55 56
};

57 58 59 60 61 62 63
/**
 * 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().
 */
64 65 66 67 68 69 70
event *
ev_new(pool *p)
{
  event *e = ralloc(p, &ev_class);
  return e;
}

71 72 73 74 75 76 77 78 79 80
/**
 * 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.
 */
81
inline void
82 83
ev_run(event *e)
{
84 85
  ev_postpone(e);
  e->hook(e->data);
86 87
}

88 89 90 91 92 93 94 95
/**
 * 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().
 */
96 97 98
inline void
ev_enqueue(event_list *l, event *e)
{
99
  ev_postpone(e);
100 101 102
  add_tail(l, &e->n);
}

103 104 105 106 107 108 109 110
/**
 * 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.
 */
111 112 113 114 115 116
void
ev_schedule(event *e)
{
  ev_enqueue(&global_event_list, e);
}

117 118
void io_log_event(void *hook, void *data);

119 120 121 122 123 124
/**
 * ev_run_list - run an event list
 * @l: an event list
 *
 * This function calls ev_run() for all events enqueued in the list @l.
 */
125
int
126 127
ev_run_list(event_list *l)
{
128
  node *n;
129
  list tmp_list;
130

131 132 133
  init_list(&tmp_list);
  add_tail_list(&tmp_list, l);
  init_list(l);
134
  WALK_LIST_FIRST(n, tmp_list)
135
    {
136
      event *e = SKIP_BACK(event, n, n);
137 138 139 140 141

      /* This is ugly hack, we want to log just events executed from the main I/O loop */
      if (l == &global_event_list)
	io_log_event(e->hook, e->data);

142
      ev_run(e);
143
    }
144
  return !EMPTY_LIST(*l);
145
}