]> jfr.im git - solanum.git/blob - libratbox/src/event.c
Merge branch 'master' of github.com:charybdis-ircd/charybdis
[solanum.git] / libratbox / src / event.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * event.c: Event functions.
4 *
5 * Copyright (C) 1998-2000 Regents of the University of California
6 * Copyright (C) 2001-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * Code borrowed from the squid web cache by Adrian Chadd.
10 * Original header:
11 *
12 * DEBUG: section 41 Event Processing
13 * AUTHOR: Henrik Nordstrom
14 *
15 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
16 * ----------------------------------------------------------
17 *
18 * Squid is the result of efforts by numerous individuals from the
19 * Internet community. Development is led by Duane Wessels of the
20 * National Laboratory for Applied Network Research and funded by the
21 * National Science Foundation. Squid is Copyrighted (C) 1998 by
22 * the Regents of the University of California. Please see the
23 * COPYRIGHT file for full details. Squid incorporates software
24 * developed and/or copyrighted by other sources. Please see the
25 * CREDITS file for full details.
26 *
27 * This program is free software; you can redistribute it and/or modify
28 * it under the terms of the GNU General Public License as published by
29 * the Free Software Foundation; either version 2 of the License, or
30 * (at your option) any later version.
31 *
32 * This program is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 * GNU General Public License for more details.
36 *
37 * You should have received a copy of the GNU General Public License
38 * along with this program; if not, write to the Free Software
39 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
40 * USA
41 *
42 * $Id: event.c 26272 2008-12-10 05:55:10Z androsyn $
43 */
44
45 #include <libratbox_config.h>
46 #include <ratbox_lib.h>
47 #include <commio-int.h>
48 #include <event-int.h>
49
50 #define EV_NAME_LEN 33
51 static char last_event_ran[EV_NAME_LEN];
52 static rb_dlink_list event_list;
53
54 static time_t event_time_min = -1;
55
56 /*
57 * struct ev_entry *
58 * rb_event_find(EVH *func, void *arg)
59 *
60 * Input: Event function and the argument passed to it
61 * Output: Index to the slow in the event_table
62 * Side Effects: None
63 */
64 static struct ev_entry *
65 rb_event_find(EVH * func, void *arg)
66 {
67 rb_dlink_node *ptr;
68 struct ev_entry *ev;
69 RB_DLINK_FOREACH(ptr, event_list.head)
70 {
71 ev = ptr->data;
72 if((ev->func == func) && (ev->arg == arg))
73 return ev;
74 }
75
76 return NULL;
77 }
78
79 static
80 struct ev_entry *
81 rb_event_add_common(const char *name, EVH * func, void *arg, time_t when, time_t frequency)
82 {
83 struct ev_entry *ev;
84 ev = rb_malloc(sizeof(struct ev_entry));
85 ev->func = func;
86 ev->name = rb_strndup(name, EV_NAME_LEN);
87 ev->arg = arg;
88 ev->when = rb_current_time() + when;
89 ev->next = when;
90 ev->frequency = frequency;
91
92 if((ev->when < event_time_min) || (event_time_min == -1))
93 event_time_min = ev->when;
94
95 rb_dlinkAdd(ev, &ev->node, &event_list);
96 rb_io_sched_event(ev, when);
97 return ev;
98 }
99
100 /*
101 * struct ev_entry *
102 * rb_event_add(const char *name, EVH *func, void *arg, time_t when)
103 *
104 * Input: Name of event, function to call, arguments to pass, and frequency
105 * of the event.
106 * Output: None
107 * Side Effects: Adds the event to the event list.
108 */
109 struct ev_entry *
110 rb_event_add(const char *name, EVH * func, void *arg, time_t when)
111 {
112 if (rb_unlikely(when <= 0)) {
113 rb_lib_log("rb_event_add: tried to schedule %s event with a delay of "
114 "%d seconds", name, (int) when);
115 when = 1;
116 }
117
118 return rb_event_add_common(name, func, arg, when, when);
119 }
120
121 struct ev_entry *
122 rb_event_addonce(const char *name, EVH * func, void *arg, time_t when)
123 {
124 if (rb_unlikely(when <= 0)) {
125 rb_lib_log("rb_event_addonce: tried to schedule %s event to run in "
126 "%d seconds", name, (int) when);
127 when = 1;
128 }
129
130 return rb_event_add_common(name, func, arg, when, 0);
131 }
132
133 /*
134 * void rb_event_delete(struct ev_entry *ev)
135 *
136 * Input: pointer to ev_entry for the event
137 * Output: None
138 * Side Effects: Removes the event from the event list
139 */
140 void
141 rb_event_delete(struct ev_entry *ev)
142 {
143 if(ev == NULL)
144 return;
145
146 rb_dlinkDelete(&ev->node, &event_list);
147 rb_io_unsched_event(ev);
148 rb_free(ev->name);
149 rb_free(ev);
150 }
151
152 /*
153 * void rb_event_find_delete(EVH *func, void *arg)
154 *
155 * Input: pointer to func and data
156 * Output: None
157 * Side Effects: Removes the event from the event list
158 */
159 void
160 rb_event_find_delete(EVH * func, void *arg)
161 {
162 rb_event_delete(rb_event_find(func, arg));
163 }
164
165 static time_t
166 rb_event_frequency(time_t frequency)
167 {
168 if(frequency < 0)
169 {
170 const time_t two_third = (2 * labs(frequency)) / 3;
171 frequency = two_third + ((rand() % 1000) * two_third) / 1000;
172 }
173 return frequency;
174 }
175
176 /*
177 * struct ev_entry *
178 * rb_event_addish(const char *name, EVH *func, void *arg, time_t delta_isa)
179 *
180 * Input: Name of event, function to call, arguments to pass, and frequency
181 * of the event.
182 * Output: None
183 * Side Effects: Adds the event to the event list within +- 1/3 of the
184 * specified frequency.
185 */
186 struct ev_entry *
187 rb_event_addish(const char *name, EVH * func, void *arg, time_t delta_ish)
188 {
189 delta_ish = labs(delta_ish);
190 if(delta_ish >= 3.0)
191 delta_ish = -delta_ish;
192 return rb_event_add_common(name, func, arg,
193 rb_event_frequency(delta_ish), delta_ish);
194 }
195
196
197 void
198 rb_run_event(struct ev_entry *ev)
199 {
200 rb_strlcpy(last_event_ran, ev->name, sizeof(last_event_ran));
201 ev->func(ev->arg);
202 if(!ev->frequency)
203 {
204 rb_event_delete(ev);
205 return;
206 }
207 ev->when = rb_current_time() + rb_event_frequency(ev->frequency);
208 if((ev->when < event_time_min) || (event_time_min == -1))
209 event_time_min = ev->when;
210 }
211
212 /*
213 * void rb_event_run(void)
214 *
215 * Input: None
216 * Output: None
217 * Side Effects: Runs pending events in the event list
218 */
219 void
220 rb_event_run(void)
221 {
222 rb_dlink_node *ptr, *next;
223 struct ev_entry *ev;
224
225 if(rb_io_supports_event())
226 return;
227
228 event_time_min = -1;
229 RB_DLINK_FOREACH_SAFE(ptr, next, event_list.head)
230 {
231 ev = ptr->data;
232 if(ev->when <= rb_current_time())
233 {
234 rb_strlcpy(last_event_ran, ev->name, sizeof(last_event_ran));
235 ev->func(ev->arg);
236
237 /* event is scheduled more than once */
238 if(ev->frequency)
239 {
240 ev->when = rb_current_time() + rb_event_frequency(ev->frequency);
241 if((ev->when < event_time_min) || (event_time_min == -1))
242 event_time_min = ev->when;
243 }
244 else
245 {
246 rb_dlinkDelete(&ev->node, &event_list);
247 rb_free(ev);
248 }
249 }
250 else
251 {
252 if((ev->when < event_time_min) || (event_time_min == -1))
253 event_time_min = ev->when;
254 }
255 }
256 }
257
258 void
259 rb_event_io_register_all(void)
260 {
261 rb_dlink_node *ptr;
262 struct ev_entry *ev;
263
264 if(!rb_io_supports_event())
265 return;
266
267 RB_DLINK_FOREACH(ptr, event_list.head)
268 {
269 ev = ptr->data;
270 rb_io_sched_event(ev, ev->next);
271 }
272 }
273
274 /*
275 * void rb_event_init(void)
276 *
277 * Input: None
278 * Output: None
279 * Side Effects: Initializes the event system.
280 */
281 void
282 rb_event_init(void)
283 {
284 rb_strlcpy(last_event_ran, "NONE", sizeof(last_event_ran));
285 }
286
287 void
288 rb_dump_events(void (*func) (char *, void *), void *ptr)
289 {
290 int len;
291 char buf[512];
292 rb_dlink_node *dptr;
293 struct ev_entry *ev;
294 len = sizeof(buf);
295
296 snprintf(buf, len, "Last event to run: %s", last_event_ran);
297 func(buf, ptr);
298
299 rb_strlcpy(buf, "Operation Next Execution", len);
300 func(buf, ptr);
301
302 RB_DLINK_FOREACH(dptr, event_list.head)
303 {
304 ev = dptr->data;
305 snprintf(buf, len, "%-28s %-4ld seconds (frequency=%d)", ev->name,
306 ev->when - (long)rb_current_time(), (int)ev->frequency);
307 func(buf, ptr);
308 }
309 }
310
311 /*
312 * void rb_set_back_events(time_t by)
313 * Input: Time to set back events by.
314 * Output: None.
315 * Side-effects: Sets back all events by "by" seconds.
316 */
317 void
318 rb_set_back_events(time_t by)
319 {
320 rb_dlink_node *ptr;
321 struct ev_entry *ev;
322 RB_DLINK_FOREACH(ptr, event_list.head)
323 {
324 ev = ptr->data;
325 if(ev->when > by)
326 ev->when -= by;
327 else
328 ev->when = 0;
329 }
330 }
331
332 void
333 rb_event_update(struct ev_entry *ev, time_t freq)
334 {
335 if(ev == NULL)
336 return;
337
338 ev->frequency = freq;
339
340 /* update when it's scheduled to run if it's higher
341 * than the new frequency
342 */
343 time_t next = rb_event_frequency(freq);
344 if((rb_current_time() + next) < ev->when)
345 ev->when = rb_current_time() + next;
346 return;
347 }
348
349 time_t
350 rb_event_next(void)
351 {
352 return event_time_min;
353 }