xref: /iperf/src/timer.c (revision e919e8c2)
17d375156SJon Dugan /*
2da9f046fSBruce A. Mah  * iperf, Copyright (c) 2014, The Regents of the University of
3da9f046fSBruce A. Mah  * California, through Lawrence Berkeley National Laboratory (subject
4da9f046fSBruce A. Mah  * to receipt of any required approvals from the U.S. Dept. of
5da9f046fSBruce A. Mah  * Energy).  All rights reserved.
67d375156SJon Dugan  *
7da9f046fSBruce A. Mah  * If you have questions about your rights to use or distribute this
8da9f046fSBruce A. Mah  * software, please contact Berkeley Lab's Technology Transfer
9da9f046fSBruce A. Mah  * Department at [email protected].
10da9f046fSBruce A. Mah  *
11da9f046fSBruce A. Mah  * NOTICE.  This software is owned by the U.S. Department of Energy.
12da9f046fSBruce A. Mah  * As such, the U.S. Government has been granted for itself and others
13da9f046fSBruce A. Mah  * acting on its behalf a paid-up, nonexclusive, irrevocable,
14da9f046fSBruce A. Mah  * worldwide license in the Software to reproduce, prepare derivative
15da9f046fSBruce A. Mah  * works, and perform publicly and display publicly.  Beginning five
16da9f046fSBruce A. Mah  * (5) years after the date permission to assert copyright is obtained
17da9f046fSBruce A. Mah  * from the U.S. Department of Energy, and subject to any subsequent
18da9f046fSBruce A. Mah  * five (5) year renewals, the U.S. Government is granted for itself
19da9f046fSBruce A. Mah  * and others acting on its behalf a paid-up, nonexclusive,
20da9f046fSBruce A. Mah  * irrevocable, worldwide license in the Software to reproduce,
21da9f046fSBruce A. Mah  * prepare derivative works, distribute copies to the public, perform
22da9f046fSBruce A. Mah  * publicly and display publicly, and to permit others to do so.
23da9f046fSBruce A. Mah  *
24da9f046fSBruce A. Mah  * This code is distributed under a BSD style license, see the LICENSE
25da9f046fSBruce A. Mah  * file for complete information.
26ec2d0670SJef Poskanzer  *
27ec2d0670SJef Poskanzer  * Based on timers.c by Jef Poskanzer. Used with permission.
287d375156SJon Dugan  */
297d375156SJon Dugan 
300fdaab07SJon Dugan #include <sys/types.h>
31ec2d0670SJef Poskanzer #include <stdlib.h>
320fdaab07SJon Dugan 
330fdaab07SJon Dugan #include "timer.h"
34*cde81d76SBen Fox-Moore #include "iperf_time.h"
3581a2df59Skaustubhprabhu 
36ec2d0670SJef Poskanzer static Timer* timers = NULL;
37ec2d0670SJef Poskanzer static Timer* free_timers = NULL;
38ec2d0670SJef Poskanzer 
39ec2d0670SJef Poskanzer TimerClientData JunkClientData;
40ec2d0670SJef Poskanzer 
41ec2d0670SJef Poskanzer 
42ec2d0670SJef Poskanzer 
43ec2d0670SJef Poskanzer /* This is an efficiency tweak.  All the routines that need to know the
44*cde81d76SBen Fox-Moore ** current time get passed a pointer to a struct iperf_time.  If it's non-NULL
45*cde81d76SBen Fox-Moore ** it gets used, otherwise we do our own iperf_time_now() to fill it in.
46*cde81d76SBen Fox-Moore ** This lets the caller avoid extraneous iperf_time_now()s when efficiency
47ec2d0670SJef Poskanzer ** is needed, and not bother with the extra code when efficiency doesn't
48ec2d0670SJef Poskanzer ** matter too much.
49ec2d0670SJef Poskanzer */
50ec2d0670SJef Poskanzer static void
getnow(struct iperf_time * nowP,struct iperf_time * nowP2)51*cde81d76SBen Fox-Moore getnow( struct iperf_time* nowP, struct iperf_time* nowP2 )
520fdaab07SJon Dugan {
53ec2d0670SJef Poskanzer     if ( nowP != NULL )
54ec2d0670SJef Poskanzer 	*nowP2 = *nowP;
55ec2d0670SJef Poskanzer     else
56*cde81d76SBen Fox-Moore 	iperf_time_now(nowP2);
57ec2d0670SJef Poskanzer }
58c5038eeaSkaustubhprabhu 
59ec2d0670SJef Poskanzer 
60ec2d0670SJef Poskanzer static void
list_add(Timer * t)61ec2d0670SJef Poskanzer list_add( Timer* t )
62ec2d0670SJef Poskanzer {
63ec2d0670SJef Poskanzer     Timer* t2;
64ec2d0670SJef Poskanzer     Timer* t2prev;
65ec2d0670SJef Poskanzer 
66ec2d0670SJef Poskanzer     if ( timers == NULL ) {
67ec2d0670SJef Poskanzer 	/* The list is empty. */
68ec2d0670SJef Poskanzer 	timers = t;
69ec2d0670SJef Poskanzer 	t->prev = t->next = NULL;
70ec2d0670SJef Poskanzer     } else {
71*cde81d76SBen Fox-Moore 	if (iperf_time_compare(&t->time, &timers->time) < 0) {
72ec2d0670SJef Poskanzer 	    /* The new timer goes at the head of the list. */
73ec2d0670SJef Poskanzer 	    t->prev = NULL;
74ec2d0670SJef Poskanzer 	    t->next = timers;
75ec2d0670SJef Poskanzer 	    timers->prev = t;
76ec2d0670SJef Poskanzer 	    timers = t;
77ec2d0670SJef Poskanzer 	} else {
78ec2d0670SJef Poskanzer 	    /* Walk the list to find the insertion point. */
79ec2d0670SJef Poskanzer 	    for ( t2prev = timers, t2 = timers->next; t2 != NULL;
80ec2d0670SJef Poskanzer 		  t2prev = t2, t2 = t2->next ) {
81*cde81d76SBen Fox-Moore 		if (iperf_time_compare(&t->time, &t2->time) < 0) {
82ec2d0670SJef Poskanzer 		    /* Found it. */
83ec2d0670SJef Poskanzer 		    t2prev->next = t;
84ec2d0670SJef Poskanzer 		    t->prev = t2prev;
85ec2d0670SJef Poskanzer 		    t->next = t2;
86ec2d0670SJef Poskanzer 		    t2->prev = t;
87ec2d0670SJef Poskanzer 		    return;
88ec2d0670SJef Poskanzer 		}
89ec2d0670SJef Poskanzer 	    }
90ec2d0670SJef Poskanzer 	    /* Oops, got to the end of the list.  Add to tail. */
91ec2d0670SJef Poskanzer 	    t2prev->next = t;
92ec2d0670SJef Poskanzer 	    t->prev = t2prev;
93ec2d0670SJef Poskanzer 	    t->next = NULL;
94ec2d0670SJef Poskanzer 	}
95ec2d0670SJef Poskanzer     }
96ec2d0670SJef Poskanzer }
97ec2d0670SJef Poskanzer 
98ec2d0670SJef Poskanzer 
99ec2d0670SJef Poskanzer static void
list_remove(Timer * t)100ec2d0670SJef Poskanzer list_remove( Timer* t )
101ec2d0670SJef Poskanzer {
102ec2d0670SJef Poskanzer     if ( t->prev == NULL )
103ec2d0670SJef Poskanzer 	timers = t->next;
104ec2d0670SJef Poskanzer     else
105ec2d0670SJef Poskanzer 	t->prev->next = t->next;
106ec2d0670SJef Poskanzer     if ( t->next != NULL )
107ec2d0670SJef Poskanzer 	t->next->prev = t->prev;
108ec2d0670SJef Poskanzer }
109ec2d0670SJef Poskanzer 
110ec2d0670SJef Poskanzer 
111ec2d0670SJef Poskanzer static void
list_resort(Timer * t)112ec2d0670SJef Poskanzer list_resort( Timer* t )
113ec2d0670SJef Poskanzer {
114ec2d0670SJef Poskanzer     /* Remove the timer from the list. */
115ec2d0670SJef Poskanzer     list_remove( t );
116ec2d0670SJef Poskanzer     /* And add it back in, sorted correctly. */
117ec2d0670SJef Poskanzer     list_add( t );
118ec2d0670SJef Poskanzer }
119ec2d0670SJef Poskanzer 
120ec2d0670SJef Poskanzer 
121ec2d0670SJef Poskanzer Timer*
tmr_create(struct iperf_time * nowP,TimerProc * timer_proc,TimerClientData client_data,int64_t usecs,int periodic)122ec2d0670SJef Poskanzer tmr_create(
123*cde81d76SBen Fox-Moore     struct iperf_time* nowP, TimerProc* timer_proc, TimerClientData client_data,
124ec2d0670SJef Poskanzer     int64_t usecs, int periodic )
125ec2d0670SJef Poskanzer {
126*cde81d76SBen Fox-Moore     struct iperf_time now;
127ec2d0670SJef Poskanzer     Timer* t;
128da54a271SBrian Tierney 
129ec2d0670SJef Poskanzer     getnow( nowP, &now );
130ff385f98Ssethdelliott 
131ec2d0670SJef Poskanzer     if ( free_timers != NULL ) {
132ec2d0670SJef Poskanzer 	t = free_timers;
133ec2d0670SJef Poskanzer 	free_timers = t->next;
134ec2d0670SJef Poskanzer     } else {
135ec2d0670SJef Poskanzer 	t = (Timer*) malloc( sizeof(Timer) );
136ec2d0670SJef Poskanzer 	if ( t == NULL )
137ec2d0670SJef Poskanzer 	    return NULL;
138aa9ca268Skaustubhprabhu     }
139aa9ca268Skaustubhprabhu 
140ec2d0670SJef Poskanzer     t->timer_proc = timer_proc;
141ec2d0670SJef Poskanzer     t->client_data = client_data;
142ec2d0670SJef Poskanzer     t->usecs = usecs;
143ec2d0670SJef Poskanzer     t->periodic = periodic;
144ec2d0670SJef Poskanzer     t->time = now;
145*cde81d76SBen Fox-Moore     iperf_time_add_usecs(&t->time, usecs);
146ec2d0670SJef Poskanzer     /* Add the new timer to the active list. */
147ec2d0670SJef Poskanzer     list_add( t );
148ec2d0670SJef Poskanzer 
149ec2d0670SJef Poskanzer     return t;
150ec2d0670SJef Poskanzer }
151ec2d0670SJef Poskanzer 
152ec2d0670SJef Poskanzer 
153ec2d0670SJef Poskanzer struct timeval*
tmr_timeout(struct iperf_time * nowP)154*cde81d76SBen Fox-Moore tmr_timeout( struct iperf_time* nowP )
155c6ffef11Skaustubhprabhu {
156*cde81d76SBen Fox-Moore     struct iperf_time now, diff;
157ec2d0670SJef Poskanzer     int64_t usecs;
158*cde81d76SBen Fox-Moore     int past;
159ec2d0670SJef Poskanzer     static struct timeval timeout;
160ec2d0670SJef Poskanzer 
161ec2d0670SJef Poskanzer     getnow( nowP, &now );
162ec2d0670SJef Poskanzer     /* Since the list is sorted, we only need to look at the first timer. */
163ec2d0670SJef Poskanzer     if ( timers == NULL )
164ec2d0670SJef Poskanzer 	return NULL;
165*cde81d76SBen Fox-Moore     past = iperf_time_diff(&timers->time, &now, &diff);
166*cde81d76SBen Fox-Moore     if (past)
167ec2d0670SJef Poskanzer         usecs = 0;
168*cde81d76SBen Fox-Moore     else
169*cde81d76SBen Fox-Moore         usecs = iperf_time_in_usecs(&diff);
170037c0c23SJef Poskanzer     timeout.tv_sec = usecs / 1000000LL;
171037c0c23SJef Poskanzer     timeout.tv_usec = usecs % 1000000LL;
172ec2d0670SJef Poskanzer     return &timeout;
173c6ffef11Skaustubhprabhu }
174ff385f98Ssethdelliott 
1750fdaab07SJon Dugan 
1760fdaab07SJon Dugan void
tmr_run(struct iperf_time * nowP)177*cde81d76SBen Fox-Moore tmr_run( struct iperf_time* nowP )
1780fdaab07SJon Dugan {
179*cde81d76SBen Fox-Moore     struct iperf_time now;
180ec2d0670SJef Poskanzer     Timer* t;
181ec2d0670SJef Poskanzer     Timer* next;
182ec2d0670SJef Poskanzer 
183ec2d0670SJef Poskanzer     getnow( nowP, &now );
184ec2d0670SJef Poskanzer     for ( t = timers; t != NULL; t = next ) {
185ec2d0670SJef Poskanzer 	next = t->next;
186ec2d0670SJef Poskanzer 	/* Since the list is sorted, as soon as we find a timer
187ec2d0670SJef Poskanzer 	** that isn't ready yet, we are done.
188ec2d0670SJef Poskanzer 	*/
189*cde81d76SBen Fox-Moore 	if (iperf_time_compare(&t->time, &now) > 0)
190ec2d0670SJef Poskanzer 	    break;
191ec2d0670SJef Poskanzer 	(t->timer_proc)( t->client_data, &now );
192ec2d0670SJef Poskanzer 	if ( t->periodic ) {
193ec2d0670SJef Poskanzer 	    /* Reschedule. */
194*cde81d76SBen Fox-Moore 	    iperf_time_add_usecs(&t->time, t->usecs);
195ec2d0670SJef Poskanzer 	    list_resort( t );
196ec2d0670SJef Poskanzer 	} else
197ec2d0670SJef Poskanzer 	    tmr_cancel( t );
198ec2d0670SJef Poskanzer     }
1990fdaab07SJon Dugan }
2000fdaab07SJon Dugan 
201a7253334SBrian Tierney 
202ec2d0670SJef Poskanzer void
tmr_reset(struct iperf_time * nowP,Timer * t)203*cde81d76SBen Fox-Moore tmr_reset( struct iperf_time* nowP, Timer* t )
204c6ffef11Skaustubhprabhu {
205*cde81d76SBen Fox-Moore     struct iperf_time now;
206ff385f98Ssethdelliott 
207ec2d0670SJef Poskanzer     getnow( nowP, &now );
208ec2d0670SJef Poskanzer     t->time = now;
209*cde81d76SBen Fox-Moore     iperf_time_add_usecs( &t->time, t->usecs );
210ec2d0670SJef Poskanzer     list_resort( t );
211ec2d0670SJef Poskanzer }
212ff385f98Ssethdelliott 
213c6ffef11Skaustubhprabhu 
214ec2d0670SJef Poskanzer void
tmr_cancel(Timer * t)215ec2d0670SJef Poskanzer tmr_cancel( Timer* t )
216ec2d0670SJef Poskanzer {
217ec2d0670SJef Poskanzer     /* Remove it from the active list. */
218ec2d0670SJef Poskanzer     list_remove( t );
219ec2d0670SJef Poskanzer     /* And put it on the free list. */
220ec2d0670SJef Poskanzer     t->next = free_timers;
221ec2d0670SJef Poskanzer     free_timers = t;
222ec2d0670SJef Poskanzer     t->prev = NULL;
223ec2d0670SJef Poskanzer }
224c6ffef11Skaustubhprabhu 
225ec2d0670SJef Poskanzer 
226ec2d0670SJef Poskanzer void
tmr_cleanup(void)227ec2d0670SJef Poskanzer tmr_cleanup( void )
228ec2d0670SJef Poskanzer {
229ec2d0670SJef Poskanzer     Timer* t;
230ec2d0670SJef Poskanzer 
231ec2d0670SJef Poskanzer     while ( free_timers != NULL ) {
232ec2d0670SJef Poskanzer 	t = free_timers;
233ec2d0670SJef Poskanzer 	free_timers = t->next;
234ec2d0670SJef Poskanzer 	free( (void*) t );
235ec2d0670SJef Poskanzer     }
236ec2d0670SJef Poskanzer }
237ec2d0670SJef Poskanzer 
238ec2d0670SJef Poskanzer 
239ec2d0670SJef Poskanzer void
tmr_destroy(void)240ec2d0670SJef Poskanzer tmr_destroy( void )
241ec2d0670SJef Poskanzer {
242ec2d0670SJef Poskanzer     while ( timers != NULL )
243ec2d0670SJef Poskanzer 	tmr_cancel( timers );
244ec2d0670SJef Poskanzer     tmr_cleanup();
245c6ffef11Skaustubhprabhu }
246