2 * snmp_alarm.c: generic library based alarm timers for various parts
6 #include <net-snmp/net-snmp-config.h>
15 #include <sys/types.h>
17 #include <netinet/in.h>
20 #if TIME_WITH_SYS_TIME
22 # include <sys/timeb.h>
24 # include <sys/time.h>
29 # include <sys/time.h>
42 #include <net-snmp/types.h>
43 #include <net-snmp/output_api.h>
44 #include <net-snmp/config_api.h>
45 #include <net-snmp/utilities.h>
47 #include <net-snmp/library/snmp_api.h>
48 #include <net-snmp/library/callback.h>
49 #include <net-snmp/library/snmp_alarm.h>
51 static struct snmp_alarm *thealarms = NULL;
52 static int start_alarms = 0;
53 static unsigned int regnum = 1;
56 init_alarm_post_config(int majorid, int minorid, void *serverarg,
61 return SNMPERR_SUCCESS;
68 snmp_register_callback(SNMP_CALLBACK_LIBRARY,
69 SNMP_CALLBACK_POST_READ_CONFIG,
70 init_alarm_post_config, NULL);
74 sa_update_entry(struct snmp_alarm *a)
76 if (a->t.tv_sec == 0 && a->t.tv_usec == 0) {
77 DEBUGMSGTL(("snmp_alarm",
78 "update_entry: illegal interval specified\n"));
82 if (a->t_last.tv_sec == 0 && a->t_last.tv_usec == 0) {
85 * Never been called yet, call time `t' from now.
87 gettimeofday(&t_now, NULL);
89 a->t_last.tv_sec = t_now.tv_sec;
90 a->t_last.tv_usec = t_now.tv_usec;
92 a->t_next.tv_sec = t_now.tv_sec + a->t.tv_sec;
93 a->t_next.tv_usec = t_now.tv_usec + a->t.tv_usec;
95 while (a->t_next.tv_usec >= 1000000) {
96 a->t_next.tv_usec -= 1000000;
97 a->t_next.tv_sec += 1;
99 } else if (a->t_next.tv_sec == 0 && a->t_next.tv_usec == 0) {
101 * We've been called but not reset for the next call.
103 if (a->flags & SA_REPEAT) {
104 a->t_next.tv_sec = a->t_last.tv_sec + a->t.tv_sec;
105 a->t_next.tv_usec = a->t_last.tv_usec + a->t.tv_usec;
107 while (a->t_next.tv_usec >= 1000000) {
108 a->t_next.tv_usec -= 1000000;
109 a->t_next.tv_sec += 1;
113 * Single time call, remove it.
115 snmp_alarm_unregister(a->clientreg);
121 snmp_alarm_unregister(unsigned int clientreg)
123 struct snmp_alarm *sa_ptr, **prevNext = &thealarms;
125 for (sa_ptr = thealarms;
126 sa_ptr != NULL && sa_ptr->clientreg != clientreg;
127 sa_ptr = sa_ptr->next) {
128 prevNext = &(sa_ptr->next);
131 if (sa_ptr != NULL) {
132 *prevNext = sa_ptr->next;
133 DEBUGMSGTL(("snmp_alarm", "unregistered alarm %d\n",
136 * Note: do not free the clientarg, its the clients responsibility
140 DEBUGMSGTL(("snmp_alarm", "no alarm %d to unregister\n", clientreg));
145 snmp_alarm_unregister_all(void)
147 struct snmp_alarm *sa_ptr, *sa_tmp;
149 for (sa_ptr = thealarms; sa_ptr != NULL; sa_ptr = sa_tmp) {
150 sa_tmp = sa_ptr->next;
153 DEBUGMSGTL(("snmp_alarm", "ALL alarms unregistered\n"));
160 struct snmp_alarm *a, *lowest = NULL;
162 for (a = thealarms; a != NULL; a = a->next) {
163 if (lowest == NULL) {
165 } else if (a->t_next.tv_sec == lowest->t_next.tv_sec) {
166 if (a->t_next.tv_usec < lowest->t_next.tv_usec) {
169 } else if (a->t_next.tv_sec < lowest->t_next.tv_sec) {
177 sa_find_specific(unsigned int clientreg)
179 struct snmp_alarm *sa_ptr;
180 for (sa_ptr = thealarms; sa_ptr != NULL; sa_ptr = sa_ptr->next) {
181 if (sa_ptr->clientreg == clientreg) {
192 struct snmp_alarm *a = NULL;
193 unsigned int clientreg;
194 struct timeval t_now;
197 * Loop through everything we have repeatedly looking for the next thing to
198 * call until all events are finally in the future again.
202 if ((a = sa_find_next()) == NULL) {
206 gettimeofday(&t_now, NULL);
208 if ((a->t_next.tv_sec < t_now.tv_sec) ||
209 ((a->t_next.tv_sec == t_now.tv_sec) &&
210 (a->t_next.tv_usec < t_now.tv_usec))) {
211 clientreg = a->clientreg;
212 DEBUGMSGTL(("snmp_alarm", "run alarm %d\n", clientreg));
213 (*(a->thecallback)) (clientreg, a->clientarg);
214 DEBUGMSGTL(("snmp_alarm", "alarm %d completed\n", clientreg));
216 if ((a = sa_find_specific(clientreg)) != NULL) {
217 a->t_last.tv_sec = t_now.tv_sec;
218 a->t_last.tv_usec = t_now.tv_usec;
219 a->t_next.tv_sec = 0;
220 a->t_next.tv_usec = 0;
223 DEBUGMSGTL(("snmp_alarm", "alarm %d deleted itself\n",
244 get_next_alarm_delay_time(struct timeval *delta)
246 struct snmp_alarm *sa_ptr;
247 struct timeval t_diff, t_now;
249 sa_ptr = sa_find_next();
252 gettimeofday(&t_now, 0);
254 if ((t_now.tv_sec > sa_ptr->t_next.tv_sec) ||
255 ((t_now.tv_sec == sa_ptr->t_next.tv_sec) &&
256 (t_now.tv_usec > sa_ptr->t_next.tv_usec))) {
258 * Time has already passed. Return the smallest possible amount of
263 return sa_ptr->clientreg;
266 * Time is still in the future.
268 t_diff.tv_sec = sa_ptr->t_next.tv_sec - t_now.tv_sec;
269 t_diff.tv_usec = sa_ptr->t_next.tv_usec - t_now.tv_usec;
271 while (t_diff.tv_usec < 0) {
273 t_diff.tv_usec += 1000000;
276 delta->tv_sec = t_diff.tv_sec;
277 delta->tv_usec = t_diff.tv_usec;
278 return sa_ptr->clientreg;
292 struct timeval delta;
293 int nextalarm = get_next_alarm_delay_time(&delta);
296 * We don't use signals if they asked us nicely not to. It's expected
297 * they'll check the next alarm time and do their own calling of
301 if (nextalarm && !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
302 NETSNMP_DS_LIB_ALARM_DONT_USE_SIG)) {
304 # ifdef HAVE_SETITIMER
307 it.it_value.tv_sec = delta.tv_sec;
308 it.it_value.tv_usec = delta.tv_usec;
309 it.it_interval.tv_sec = 0;
310 it.it_interval.tv_usec = 0;
312 signal(SIGALRM, alarm_handler);
313 setitimer(ITIMER_REAL, &it, NULL);
314 DEBUGMSGTL(("snmp_alarm", "schedule alarm %d in %d.%03d seconds\n",
315 nextalarm, delta.tv_sec, (delta.tv_usec / 1000)));
316 # else /* HAVE_SETITIMER */
318 signal(SIGALRM, alarm_handler);
320 DEBUGMSGTL(("snmp_alarm",
321 "schedule alarm %d in roughly %d seconds\n", nextalarm,
323 # endif /* SIGALRM */
324 # endif /* HAVE_SETITIMER */
328 DEBUGMSGTL(("snmp_alarm", "no alarms found to schedule\n"));
335 snmp_alarm_register(unsigned int when, unsigned int flags,
336 SNMPAlarmCallback * thecallback, void *clientarg)
338 struct snmp_alarm **sa_pptr;
339 if (thealarms != NULL) {
340 for (sa_pptr = &thealarms; (*sa_pptr) != NULL;
341 sa_pptr = &((*sa_pptr)->next));
343 sa_pptr = &thealarms;
346 *sa_pptr = SNMP_MALLOC_STRUCT(snmp_alarm);
347 if (*sa_pptr == NULL)
350 (*sa_pptr)->t.tv_sec = when;
351 (*sa_pptr)->t.tv_usec = 0;
352 (*sa_pptr)->flags = flags;
353 (*sa_pptr)->clientarg = clientarg;
354 (*sa_pptr)->thecallback = thecallback;
355 (*sa_pptr)->clientreg = regnum++;
356 (*sa_pptr)->next = NULL;
357 sa_update_entry(*sa_pptr);
359 DEBUGMSGTL(("snmp_alarm",
360 "registered alarm %d, t = %d.%03d, flags=0x%02x\n",
361 (*sa_pptr)->clientreg, (*sa_pptr)->t.tv_sec,
362 ((*sa_pptr)->t.tv_usec / 1000), (*sa_pptr)->flags));
366 return (*sa_pptr)->clientreg;
372 snmp_alarm_register_hr(struct timeval t, unsigned int flags,
373 SNMPAlarmCallback * cb, void *cd)
375 struct snmp_alarm **s = NULL;
377 for (s = &(thealarms); *s != NULL; s = &((*s)->next));
379 *s = SNMP_MALLOC_STRUCT(snmp_alarm);
384 (*s)->t.tv_sec = t.tv_sec;
385 (*s)->t.tv_usec = t.tv_usec;
387 (*s)->clientarg = cd;
388 (*s)->thecallback = cb;
389 (*s)->clientreg = regnum++;
394 DEBUGMSGTL(("snmp_alarm",
395 "registered alarm %d, t = %d.%03d, flags=0x%02x\n",
396 (*s)->clientreg, (*s)->t.tv_sec, ((*s)->t.tv_usec / 1000),
403 return (*s)->clientreg;