Home | History | Annotate | Line # | Download | only in mrouted
      1 /*	$NetBSD: callout.c,v 1.7 2003/03/05 21:05:38 wiz 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(void);
     30 #else
     31 #define	print_Q()
     32 #endif
     33 
     34 int secs_remaining(int);
     35 
     36 void
     37 callout_init(void)
     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(void)
     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 	    logit(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  * delay: number of units for timeout
     87  * action: function to be called on timeout
     88  * data: what to call the timeout function with
     89  */
     90 int
     91 timer_setTimer(int delay, cfunc_t action, char *data)
     92 {
     93     struct     timeout_q  *ptr, *node, *prev;
     94 
     95     if (in_callout)
     96 	return -1;
     97 
     98     in_callout = 1;
     99 
    100     /* create a node */
    101     node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
    102     if (node == 0) {
    103 	logit(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n");
    104 	in_callout = 0;
    105 	return -1;
    106     }
    107     node->func = action;
    108     node->data = data;
    109     node->time = delay;
    110     node->next = 0;
    111     node->id   = ++id;
    112 
    113     prev = ptr = Q;
    114 
    115     /* insert node in the queue */
    116 
    117     /* if the queue is empty, insert the node and return */
    118     if (!Q)
    119 	Q = node;
    120     else {
    121 	/* chase the pointer looking for the right place */
    122 	while (ptr) {
    123 
    124 	    if (delay < ptr->time) {
    125 		/* right place */
    126 
    127 		node->next = ptr;
    128 		if (ptr == Q)
    129 		    Q = node;
    130 		else
    131 		    prev->next = node;
    132 		ptr->time -= node->time;
    133 		print_Q();
    134 		in_callout = 0;
    135 		return node->id;
    136 	    } else  {
    137 		/* keep moving */
    138 
    139 		delay -= ptr->time; node->time = delay;
    140 		prev = ptr;
    141 		ptr = ptr->next;
    142 	    }
    143 	}
    144 	prev->next = node;
    145     }
    146     print_Q();
    147     in_callout = 0;
    148     return node->id;
    149 }
    150 
    151 
    152 /* clears the associated timer */
    153 void
    154 timer_clearTimer(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(void)
    206 {
    207     struct timeout_q  *ptr;
    208 
    209     for(ptr = Q; ptr; ptr = ptr->next)
    210 	logit(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time);
    211 }
    212 #endif /* IGMP_DEBUG */
    213 
    214 int
    215 secs_remaining(int timer_id)
    216 {
    217     struct timeout_q  *ptr;
    218     int left=0;
    219 
    220     for (ptr = Q; ptr && ptr->id != timer_id; ptr = ptr->next)
    221        left += ptr->time;
    222 
    223     if (!ptr) /* not found */
    224        return 0;
    225 
    226     return left + ptr->time;
    227 }
    228