1 #include <assert.h>
2 #include <stdlib.h>
3
4 #include "mpool.h"
5
6 #include "events.h"
7 #include "events_internal.h"
8
9 struct eventq {
10 struct eventrec * r;
11 struct eventq * next;
12 struct eventq * prev;
13 int prio;
14 };
15
16 MPOOL(eventq, struct eventq, 4096);
17
18 /* First nodes in the linked lists. */
19 static struct eventq * heads[32] = {
20 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
21 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
22 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
23 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
24 };
25
26 /* For non-NULL heads[i], tails[i] is the last node in the list. */
27 static struct eventq * tails[32];
28
29 /* For i < minq, heads[i] == NULL. */
30 static int minq = 32;
31
32 /**
33 * events_immediate_register(func, cookie, prio):
34 * Register ${func}(${cookie}) to be run the next time events_run is invoked,
35 * after immediate events with smaller ${prio} values and before events with
36 * larger ${prio} values. The value ${prio} must be in the range [0, 31].
37 * Return a cookie which can be passed to events_immediate_cancel.
38 */
39 void *
events_immediate_register(int (* func)(void *),void * cookie,int prio)40 events_immediate_register(int (*func)(void *), void * cookie, int prio)
41 {
42 struct eventrec * r;
43 struct eventq * q;
44
45 /* Sanity check. */
46 assert((prio >= 0) && (prio < 32));
47
48 /* Bundle into an eventrec record. */
49 if ((r = events_mkrec(func, cookie)) == NULL)
50 goto err0;
51
52 /* Create a linked list node. */
53 if ((q = mpool_eventq_malloc()) == NULL)
54 goto err1;
55 q->r = r;
56 q->next = NULL;
57 q->prev = NULL;
58 q->prio = prio;
59
60 /* Add to the queue. */
61 if (heads[prio] == NULL) {
62 heads[prio] = q;
63 if (prio < minq)
64 minq = prio;
65 } else {
66 tails[prio]->next = q;
67 q->prev = tails[prio];
68 }
69 tails[prio] = q;
70
71 /* Success! */
72 return (q);
73
74 err1:
75 events_freerec(r);
76 err0:
77 /* Failure! */
78 return (NULL);
79 }
80
81 /**
82 * events_immediate_cancel(cookie):
83 * Cancel the immediate event for which the cookie ${cookie} was returned by
84 * events_immediate_register.
85 */
86 void
events_immediate_cancel(void * cookie)87 events_immediate_cancel(void * cookie)
88 {
89 struct eventq * q = cookie;
90 int prio = q->prio;
91
92 /* If we have a predecessor, point it at our successor. */
93 if (q->prev != NULL)
94 q->prev->next = q->next;
95 else
96 heads[prio] = q->next;
97
98 /* If we have a successor, point it at our predecessor. */
99 if (q->next != NULL)
100 q->next->prev = q->prev;
101 else
102 tails[prio] = q->prev;
103
104 /* Free the eventrec. */
105 events_freerec(q->r);
106
107 /* Return the node to the malloc pool. */
108 mpool_eventq_free(q);
109 }
110
111 /**
112 * events_immediate_get(void):
113 * Remove and return an eventrec structure from the immediate event queue,
114 * or return NULL if there are no such events. The caller is responsible for
115 * freeing the returned memory.
116 */
117 struct eventrec *
events_immediate_get(void)118 events_immediate_get(void)
119 {
120 struct eventq * q;
121 struct eventrec * r;
122
123 /* Advance past priorities which have no events. */
124 while ((minq < 32) && (heads[minq] == NULL))
125 minq++;
126
127 /* Are there any events? */
128 if (minq == 32)
129 return (NULL);
130
131 /*
132 * Remove the first node from the highest priority non-empty linked
133 * list.
134 */
135 q = heads[minq];
136 heads[minq] = q->next;
137 if (heads[minq] != NULL)
138 heads[minq]->prev = NULL;
139
140 /* Extract the eventrec. */
141 r = q->r;
142
143 /* Return the node to the malloc pool. */
144 mpool_eventq_free(q);
145
146 /* Return the eventrec. */
147 return (r);
148 }
149