1/*	$NetBSD: callout.c,v 1.3 1995/12/10 10:06:56 mycroft Exp $	*/
2
3/*
4 * The mrouted program is covered by the license in the accompanying file
5 * named "LICENSE".  Use of the mrouted program represents acceptance of
6 * the terms and conditions listed in that file.
7 *
8 * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
9 * Leland Stanford Junior University.
10 */
11
12#include "defs.h"
13
14/* the code below implements a callout queue */
15static int id = 0;
16static struct timeout_q  *Q = 0; /* pointer to the beginning of timeout queue */
17
18static int in_callout = 0;
19
20struct timeout_q {
21	struct timeout_q *next;		/* next event */
22	int		 id;
23	cfunc_t          func;		/* function to call */
24	char		 *data;		/* func's data */
25	int		 time;		/* time offset to next event*/
26};
27
28#ifdef IGMP_DEBUG
29static void print_Q(void);
30#else
31#define	print_Q()
32#endif
33
34void
35callout_init(void)
36{
37    Q = (struct timeout_q *) 0;
38}
39
40
41/*
42 * signal handler for SIGALARM that is called once every second
43 */
44void
45age_callout_queue(void)
46{
47    struct timeout_q *ptr;
48
49    if (in_callout)
50	return;
51
52    in_callout = 1;
53    ptr = Q;
54
55    while (ptr) {
56	if (!ptr->time) {
57	    /* timeout has happened */
58	    Q = Q->next;
59
60	    in_callout = 0;
61	    if (ptr->func)
62		ptr->func(ptr->data);
63	    in_callout = 1;
64
65	    free(ptr);
66	    ptr = Q;
67	}
68	else {
69	    ptr->time --;
70#ifdef IGMP_DEBUG
71	    logit(LOG_DEBUG,0,"[callout, age_callout_queue] -- time (%d)", ptr->time);
72#endif /* IGMP_DEBUG */
73	    in_callout = 0; return;
74	}
75    }
76    in_callout = 0;
77    return;
78}
79
80
81/*
82 * sets the timer
83 * delay	number of units for timeout
84 * action	function to be called on timeout
85 * data		what to call the timeout function with
86 */
87int
88timer_setTimer(int delay, cfunc_t action, char *data)
89{
90    struct     timeout_q  *ptr, *node, *prev;
91
92    if (in_callout)
93	return -1;
94
95    in_callout = 1;
96
97    /* create a node */
98    node = malloc(sizeof(struct timeout_q));
99    if (node == 0) {
100	logit(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n");
101	in_callout = 0;
102	return -1;
103    }
104    node->func = action;
105    node->data = data;
106    node->time = delay;
107    node->next = 0;
108    node->id   = ++id;
109
110    prev = ptr = Q;
111
112    /* insert node in the queue */
113
114    /* if the queue is empty, insert the node and return */
115    if (!Q)
116	Q = node;
117    else {
118	/* chase the pointer looking for the right place */
119	while (ptr) {
120
121	    if (delay < ptr->time) {
122		/* right place */
123
124		node->next = ptr;
125		if (ptr == Q)
126		    Q = node;
127		else
128		    prev->next = node;
129		ptr->time -= node->time;
130		print_Q();
131		in_callout = 0;
132		return node->id;
133	    } else  {
134		/* keep moving */
135
136		delay -= ptr->time; node->time = delay;
137		prev = ptr;
138		ptr = ptr->next;
139	    }
140	}
141	prev->next = node;
142    }
143    print_Q();
144    in_callout = 0;
145    return node->id;
146}
147
148
149/* clears the associated timer */
150void
151timer_clearTimer(int timer_id)
152{
153    struct timeout_q  *ptr, *prev;
154
155    if (in_callout)
156        return;
157    if (!timer_id)
158	return;
159
160    in_callout = 1;
161
162    prev = ptr = Q;
163
164    /*
165     * find the right node, delete it. the subsequent node's time
166     * gets bumped up
167     */
168
169    print_Q();
170    while (ptr) {
171	if (ptr->id == timer_id) {
172	    /* got the right node */
173
174	    /* unlink it from the queue */
175	    if (ptr == Q)
176		Q = Q->next;
177	    else
178		prev->next = ptr->next;
179
180	    /* increment next node if any */
181	    if (ptr->next != 0)
182		(ptr->next)->time += ptr->time;
183
184	    free(ptr->data);
185	    free(ptr);
186	    print_Q();
187	    in_callout = 0;
188	    return;
189	}
190	prev = ptr;
191	ptr = ptr->next;
192    }
193    print_Q();
194    in_callout = 0;
195}
196
197#ifdef IGMP_DEBUG
198/*
199 * debugging utility
200 */
201static void
202print_Q(void)
203{
204    struct timeout_q  *ptr;
205
206    for(ptr = Q; ptr; ptr = ptr->next)
207	logit(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time);
208}
209#endif /* IGMP_DEBUG */
210
211int
212secs_remaining(int timer_id)
213{
214    struct timeout_q  *ptr;
215    int left=0;
216
217    for (ptr = Q; ptr && ptr->id != timer_id; ptr = ptr->next)
218       left += ptr->time;
219
220    if (!ptr) /* not found */
221       return 0;
222
223    return left + ptr->time;
224}
225