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