Home | History | Annotate | Line # | Download | only in mrouted
callout.c revision 1.3
      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 */
     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 void
     35 callout_init()
     36 {
     37     Q = (struct timeout_q *) 0;
     38 }
     39 
     40 
     41 /*
     42  * signal handler for SIGALARM that is called once every second
     43  */
     44 void
     45 age_callout_queue()
     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 	    log(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  */
     84 int
     85 timer_setTimer(delay, action, data)
     86     int 	delay;  	/* number of units for timeout */
     87     cfunc_t	action; 	/* function to be called on timeout */
     88     char  	*data;  	/* what to call the timeout function with */
     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 = (struct timeout_q *)malloc(sizeof(struct timeout_q));
     99     if (node == 0) {
    100 	log(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 */
    150 void
    151 timer_clearTimer(timer_id)
    152     int  timer_id;
    153 {
    154     struct timeout_q  *ptr, *prev;
    155 
    156     if (in_callout)
    157         return;
    158     if (!timer_id)
    159 	return;
    160 
    161     in_callout = 1;
    162 
    163     prev = ptr = Q;
    164 
    165     /*
    166      * find the right node, delete it. the subsequent node's time
    167      * gets bumped up
    168      */
    169 
    170     print_Q();
    171     while (ptr) {
    172 	if (ptr->id == timer_id) {
    173 	    /* got the right node */
    174 
    175 	    /* unlink it from the queue */
    176 	    if (ptr == Q)
    177 		Q = Q->next;
    178 	    else
    179 		prev->next = ptr->next;
    180 
    181 	    /* increment next node if any */
    182 	    if (ptr->next != 0)
    183 		(ptr->next)->time += ptr->time;
    184 
    185 	    free(ptr->data);
    186 	    free(ptr);
    187 	    print_Q();
    188 	    in_callout = 0;
    189 	    return;
    190 	}
    191 	prev = ptr;
    192 	ptr = ptr->next;
    193     }
    194     print_Q();
    195     in_callout = 0;
    196 }
    197 
    198 #ifdef IGMP_DEBUG
    199 /*
    200  * debugging utility
    201  */
    202 static void
    203 print_Q()
    204 {
    205     struct timeout_q  *ptr;
    206 
    207     for(ptr = Q; ptr; ptr = ptr->next)
    208 	log(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time);
    209 }
    210 #endif /* IGMP_DEBUG */
    211 int
    212 secs_remaining( timer_id)
    213     int  timer_id;
    214 {
    215     struct timeout_q  *ptr;
    216     int left=0;
    217 
    218     for (ptr = Q; ptr && ptr->id != timer_id; ptr = ptr->next)
    219        left += ptr->time;
    220 
    221     if (!ptr) /* not found */
    222        return 0;
    223 
    224     return left + ptr->time;
    225 }
    226