xref: /iperf/src/timer.c (revision ec2d0670)
17d375156SJon Dugan /*
27d375156SJon Dugan  * Copyright (c) 2009-2011, The Regents of the University of California,
37d375156SJon Dugan  * through Lawrence Berkeley National Laboratory (subject to receipt of any
47d375156SJon Dugan  * required approvals from the U.S. Dept. of Energy).  All rights reserved.
57d375156SJon Dugan  *
67d375156SJon Dugan  * This code is distributed under a BSD style license, see the LICENSE file
77d375156SJon Dugan  * for complete information.
8*ec2d0670SJef Poskanzer  *
9*ec2d0670SJef Poskanzer  * Based on timers.c by Jef Poskanzer. Used with permission.
107d375156SJon Dugan  */
117d375156SJon Dugan 
120fdaab07SJon Dugan #include <sys/types.h>
13*ec2d0670SJef Poskanzer #include <stdlib.h>
140fdaab07SJon Dugan 
150fdaab07SJon Dugan #include "timer.h"
160fdaab07SJon Dugan 
1781a2df59Skaustubhprabhu 
18*ec2d0670SJef Poskanzer static Timer* timers = NULL;
19*ec2d0670SJef Poskanzer static Timer* free_timers = NULL;
20*ec2d0670SJef Poskanzer 
21*ec2d0670SJef Poskanzer TimerClientData JunkClientData;
22*ec2d0670SJef Poskanzer 
23*ec2d0670SJef Poskanzer 
24*ec2d0670SJef Poskanzer 
25*ec2d0670SJef Poskanzer /* This is an efficiency tweak.  All the routines that need to know the
26*ec2d0670SJef Poskanzer ** current time get passed a pointer to a struct timeval.  If it's non-NULL
27*ec2d0670SJef Poskanzer ** it gets used, otherwise we do our own gettimeofday() to fill it in.
28*ec2d0670SJef Poskanzer ** This lets the caller avoid extraneous gettimeofday()s when efficiency
29*ec2d0670SJef Poskanzer ** is needed, and not bother with the extra code when efficiency doesn't
30*ec2d0670SJef Poskanzer ** matter too much.
31*ec2d0670SJef Poskanzer */
32*ec2d0670SJef Poskanzer static void
33*ec2d0670SJef Poskanzer getnow( struct timeval* nowP, struct timeval* nowP2 )
340fdaab07SJon Dugan {
35*ec2d0670SJef Poskanzer     if ( nowP != NULL )
36*ec2d0670SJef Poskanzer 	*nowP2 = *nowP;
37*ec2d0670SJef Poskanzer     else
38*ec2d0670SJef Poskanzer 	(void) gettimeofday( nowP2, NULL );
39*ec2d0670SJef Poskanzer }
40c5038eeaSkaustubhprabhu 
41*ec2d0670SJef Poskanzer 
42*ec2d0670SJef Poskanzer static void
43*ec2d0670SJef Poskanzer list_add( Timer* t )
44*ec2d0670SJef Poskanzer {
45*ec2d0670SJef Poskanzer     Timer* t2;
46*ec2d0670SJef Poskanzer     Timer* t2prev;
47*ec2d0670SJef Poskanzer 
48*ec2d0670SJef Poskanzer     if ( timers == NULL ) {
49*ec2d0670SJef Poskanzer 	/* The list is empty. */
50*ec2d0670SJef Poskanzer 	timers = t;
51*ec2d0670SJef Poskanzer 	t->prev = t->next = NULL;
52*ec2d0670SJef Poskanzer     } else {
53*ec2d0670SJef Poskanzer 	if ( t->time.tv_sec < timers->time.tv_sec ||
54*ec2d0670SJef Poskanzer 	     ( t->time.tv_sec == timers->time.tv_sec &&
55*ec2d0670SJef Poskanzer 	       t->time.tv_usec < timers->time.tv_usec ) ) {
56*ec2d0670SJef Poskanzer 	    /* The new timer goes at the head of the list. */
57*ec2d0670SJef Poskanzer 	    t->prev = NULL;
58*ec2d0670SJef Poskanzer 	    t->next = timers;
59*ec2d0670SJef Poskanzer 	    timers->prev = t;
60*ec2d0670SJef Poskanzer 	    timers = t;
61*ec2d0670SJef Poskanzer 	} else {
62*ec2d0670SJef Poskanzer 	    /* Walk the list to find the insertion point. */
63*ec2d0670SJef Poskanzer 	    for ( t2prev = timers, t2 = timers->next; t2 != NULL;
64*ec2d0670SJef Poskanzer 		  t2prev = t2, t2 = t2->next ) {
65*ec2d0670SJef Poskanzer 		if ( t->time.tv_sec < t2->time.tv_sec ||
66*ec2d0670SJef Poskanzer 		     ( t->time.tv_sec == t2->time.tv_sec &&
67*ec2d0670SJef Poskanzer 		       t->time.tv_usec < t2->time.tv_usec ) ) {
68*ec2d0670SJef Poskanzer 		    /* Found it. */
69*ec2d0670SJef Poskanzer 		    t2prev->next = t;
70*ec2d0670SJef Poskanzer 		    t->prev = t2prev;
71*ec2d0670SJef Poskanzer 		    t->next = t2;
72*ec2d0670SJef Poskanzer 		    t2->prev = t;
73*ec2d0670SJef Poskanzer 		    return;
74*ec2d0670SJef Poskanzer 		}
75*ec2d0670SJef Poskanzer 	    }
76*ec2d0670SJef Poskanzer 	    /* Oops, got to the end of the list.  Add to tail. */
77*ec2d0670SJef Poskanzer 	    t2prev->next = t;
78*ec2d0670SJef Poskanzer 	    t->prev = t2prev;
79*ec2d0670SJef Poskanzer 	    t->next = NULL;
80*ec2d0670SJef Poskanzer 	}
81*ec2d0670SJef Poskanzer     }
82*ec2d0670SJef Poskanzer }
83*ec2d0670SJef Poskanzer 
84*ec2d0670SJef Poskanzer 
85*ec2d0670SJef Poskanzer static void
86*ec2d0670SJef Poskanzer list_remove( Timer* t )
87*ec2d0670SJef Poskanzer {
88*ec2d0670SJef Poskanzer     if ( t->prev == NULL )
89*ec2d0670SJef Poskanzer 	timers = t->next;
90*ec2d0670SJef Poskanzer     else
91*ec2d0670SJef Poskanzer 	t->prev->next = t->next;
92*ec2d0670SJef Poskanzer     if ( t->next != NULL )
93*ec2d0670SJef Poskanzer 	t->next->prev = t->prev;
94*ec2d0670SJef Poskanzer }
95*ec2d0670SJef Poskanzer 
96*ec2d0670SJef Poskanzer 
97*ec2d0670SJef Poskanzer static void
98*ec2d0670SJef Poskanzer list_resort( Timer* t )
99*ec2d0670SJef Poskanzer {
100*ec2d0670SJef Poskanzer     /* Remove the timer from the list. */
101*ec2d0670SJef Poskanzer     list_remove( t );
102*ec2d0670SJef Poskanzer     /* And add it back in, sorted correctly. */
103*ec2d0670SJef Poskanzer     list_add( t );
104*ec2d0670SJef Poskanzer }
105*ec2d0670SJef Poskanzer 
106*ec2d0670SJef Poskanzer 
107*ec2d0670SJef Poskanzer static void
108*ec2d0670SJef Poskanzer add_usecs( struct timeval* t, int64_t usecs )
109*ec2d0670SJef Poskanzer {
110*ec2d0670SJef Poskanzer     t->tv_sec += usecs / 1000000L;
111*ec2d0670SJef Poskanzer     t->tv_usec += usecs % 1000000L;
112*ec2d0670SJef Poskanzer     if ( t->tv_usec >= 1000000L ) {
113*ec2d0670SJef Poskanzer 	t->tv_sec += t->tv_usec / 1000000L;
114*ec2d0670SJef Poskanzer 	t->tv_usec %= 1000000L;
115*ec2d0670SJef Poskanzer     }
116*ec2d0670SJef Poskanzer }
117*ec2d0670SJef Poskanzer 
118*ec2d0670SJef Poskanzer 
119*ec2d0670SJef Poskanzer Timer*
120*ec2d0670SJef Poskanzer tmr_create(
121*ec2d0670SJef Poskanzer     struct timeval* nowP, TimerProc* timer_proc, TimerClientData client_data,
122*ec2d0670SJef Poskanzer     int64_t usecs, int periodic )
123*ec2d0670SJef Poskanzer {
1240fdaab07SJon Dugan     struct timeval now;
125*ec2d0670SJef Poskanzer     Timer* t;
126da54a271SBrian Tierney 
127*ec2d0670SJef Poskanzer     getnow( nowP, &now );
128ff385f98Ssethdelliott 
129*ec2d0670SJef Poskanzer     if ( free_timers != NULL ) {
130*ec2d0670SJef Poskanzer 	t = free_timers;
131*ec2d0670SJef Poskanzer 	free_timers = t->next;
132*ec2d0670SJef Poskanzer     } else {
133*ec2d0670SJef Poskanzer 	t = (Timer*) malloc( sizeof(Timer) );
134*ec2d0670SJef Poskanzer 	if ( t == NULL )
135*ec2d0670SJef Poskanzer 	    return NULL;
136aa9ca268Skaustubhprabhu     }
137aa9ca268Skaustubhprabhu 
138*ec2d0670SJef Poskanzer     t->timer_proc = timer_proc;
139*ec2d0670SJef Poskanzer     t->client_data = client_data;
140*ec2d0670SJef Poskanzer     t->usecs = usecs;
141*ec2d0670SJef Poskanzer     t->periodic = periodic;
142*ec2d0670SJef Poskanzer     t->time = now;
143*ec2d0670SJef Poskanzer     add_usecs( &t->time, usecs );
144*ec2d0670SJef Poskanzer     /* Add the new timer to the active list. */
145*ec2d0670SJef Poskanzer     list_add( t );
146*ec2d0670SJef Poskanzer 
147*ec2d0670SJef Poskanzer     return t;
148*ec2d0670SJef Poskanzer }
149*ec2d0670SJef Poskanzer 
150*ec2d0670SJef Poskanzer 
151*ec2d0670SJef Poskanzer struct timeval*
152*ec2d0670SJef Poskanzer tmr_timeout( struct timeval* nowP )
153c6ffef11Skaustubhprabhu {
154*ec2d0670SJef Poskanzer     struct timeval now;
155*ec2d0670SJef Poskanzer     int64_t usecs;
156*ec2d0670SJef Poskanzer     static struct timeval timeout;
157*ec2d0670SJef Poskanzer 
158*ec2d0670SJef Poskanzer     getnow( nowP, &now );
159*ec2d0670SJef Poskanzer     /* Since the list is sorted, we only need to look at the first timer. */
160*ec2d0670SJef Poskanzer     if ( timers == NULL )
161*ec2d0670SJef Poskanzer 	return NULL;
162*ec2d0670SJef Poskanzer     usecs = ( timers->time.tv_sec - now.tv_sec ) * 1000000L +
163*ec2d0670SJef Poskanzer 	    ( timers->time.tv_usec - now.tv_usec );
164*ec2d0670SJef Poskanzer     if ( usecs <= 0 )
165*ec2d0670SJef Poskanzer 	usecs = 0;
166*ec2d0670SJef Poskanzer     timeout.tv_sec = usecs / 1000000L;
167*ec2d0670SJef Poskanzer     timeout.tv_usec = usecs % 1000000L;
168*ec2d0670SJef Poskanzer     return &timeout;
169c6ffef11Skaustubhprabhu }
170ff385f98Ssethdelliott 
1710fdaab07SJon Dugan 
1720fdaab07SJon Dugan void
173*ec2d0670SJef Poskanzer tmr_run( struct timeval* nowP )
1740fdaab07SJon Dugan {
175*ec2d0670SJef Poskanzer     struct timeval now;
176*ec2d0670SJef Poskanzer     Timer* t;
177*ec2d0670SJef Poskanzer     Timer* next;
178*ec2d0670SJef Poskanzer 
179*ec2d0670SJef Poskanzer     getnow( nowP, &now );
180*ec2d0670SJef Poskanzer     for ( t = timers; t != NULL; t = next ) {
181*ec2d0670SJef Poskanzer 	next = t->next;
182*ec2d0670SJef Poskanzer 	/* Since the list is sorted, as soon as we find a timer
183*ec2d0670SJef Poskanzer 	** that isn't ready yet, we are done.
184*ec2d0670SJef Poskanzer 	*/
185*ec2d0670SJef Poskanzer 	if ( t->time.tv_sec > now.tv_sec ||
186*ec2d0670SJef Poskanzer 	     ( t->time.tv_sec == now.tv_sec &&
187*ec2d0670SJef Poskanzer 	       t->time.tv_usec > now.tv_usec ) )
188*ec2d0670SJef Poskanzer 	    break;
189*ec2d0670SJef Poskanzer 	(t->timer_proc)( t->client_data, &now );
190*ec2d0670SJef Poskanzer 	if ( t->periodic ) {
191*ec2d0670SJef Poskanzer 	    /* Reschedule. */
192*ec2d0670SJef Poskanzer 	    add_usecs( &t->time, t->usecs );
193*ec2d0670SJef Poskanzer 	    list_resort( t );
194*ec2d0670SJef Poskanzer 	} else
195*ec2d0670SJef Poskanzer 	    tmr_cancel( t );
196*ec2d0670SJef Poskanzer     }
1970fdaab07SJon Dugan }
1980fdaab07SJon Dugan 
199a7253334SBrian Tierney 
200*ec2d0670SJef Poskanzer void
201*ec2d0670SJef Poskanzer tmr_reset( struct timeval* nowP, Timer* t )
202c6ffef11Skaustubhprabhu {
203c6ffef11Skaustubhprabhu     struct timeval now;
204ff385f98Ssethdelliott 
205*ec2d0670SJef Poskanzer     getnow( nowP, &now );
206*ec2d0670SJef Poskanzer     t->time = now;
207*ec2d0670SJef Poskanzer     add_usecs( &t->time, t->usecs );
208*ec2d0670SJef Poskanzer     list_resort( t );
209*ec2d0670SJef Poskanzer }
210ff385f98Ssethdelliott 
211c6ffef11Skaustubhprabhu 
212*ec2d0670SJef Poskanzer void
213*ec2d0670SJef Poskanzer tmr_cancel( Timer* t )
214*ec2d0670SJef Poskanzer {
215*ec2d0670SJef Poskanzer     /* Remove it from the active list. */
216*ec2d0670SJef Poskanzer     list_remove( t );
217*ec2d0670SJef Poskanzer     /* And put it on the free list. */
218*ec2d0670SJef Poskanzer     t->next = free_timers;
219*ec2d0670SJef Poskanzer     free_timers = t;
220*ec2d0670SJef Poskanzer     t->prev = NULL;
221*ec2d0670SJef Poskanzer }
222c6ffef11Skaustubhprabhu 
223*ec2d0670SJef Poskanzer 
224*ec2d0670SJef Poskanzer void
225*ec2d0670SJef Poskanzer tmr_cleanup( void )
226*ec2d0670SJef Poskanzer {
227*ec2d0670SJef Poskanzer     Timer* t;
228*ec2d0670SJef Poskanzer 
229*ec2d0670SJef Poskanzer     while ( free_timers != NULL ) {
230*ec2d0670SJef Poskanzer 	t = free_timers;
231*ec2d0670SJef Poskanzer 	free_timers = t->next;
232*ec2d0670SJef Poskanzer 	free( (void*) t );
233*ec2d0670SJef Poskanzer     }
234*ec2d0670SJef Poskanzer }
235*ec2d0670SJef Poskanzer 
236*ec2d0670SJef Poskanzer 
237*ec2d0670SJef Poskanzer void
238*ec2d0670SJef Poskanzer tmr_destroy( void )
239*ec2d0670SJef Poskanzer {
240*ec2d0670SJef Poskanzer     while ( timers != NULL )
241*ec2d0670SJef Poskanzer 	tmr_cancel( timers );
242*ec2d0670SJef Poskanzer     tmr_cleanup();
243c6ffef11Skaustubhprabhu }
244