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