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