void Timers::Execute() { timeval curTime; gettimeofday(&curTime, 0); for (Timer* s = m_firstTimer; s != 0; s = m_firstTimer) { if (CompareTimevals(s->GetNextExecution(), curTime)) break; TimerCbk_t cbk = s->GetCallback(); void* userdata = s->GetUserdata(); s->Update(); int remainingReps = s->GetRemainingRepetitions(); cbk(userdata); if (FindTimer(s)) { DeleteFromList(s); if (remainingReps == 0) delete s; else InsertTimer(s); } } }
Timer* Timers::Create(TimerCbk_t cbk, int nrep, unsigned int ms, void* userData) { if (ms < 10) return 0; Timer* newTimer = new Timer(cbk, nrep, ms, userData); InsertTimer(newTimer); return newTimer; }
/** \param pArg a pointer to a timer structure that the user has filled with desired timer properties. \sa timeElement, cancelTimer, modifyTimer */ void Timer::startTimer (p_timeElement pArg) { pArg->setTimeOut (_presentTime + pArg->getTimePeriod ()); // Set the expiration time. // Search the _timeOutList for correct insertion point to keep the list sorted. // This saves the interrupt service routine from needing to check every timer // for expiration; if timer[0] has not expired, then none have because the list // is sorted. InsertTimer (pArg); }
// Timeout() is called when a select() time out. Returns number of seconds // until next timeout event, a 0 if there are no more events, or a -1 if // called while a handler is active (i.e. handler calls Timeout; // Timeout is not re-entrant). int TimerManager::Timeout(int * pNumFired /*= NULL*/, double * pruntime /*=NULL*/) { int result, timer_check_cntr; time_t now, time_sample; int num_fires = 0; // num of handlers called in this timeout if (pNumFired) *pNumFired = 0; if ( in_timeout != NULL ) { dprintf(D_DAEMONCORE,"DaemonCore Timeout() called and in_timeout is non-NULL\n"); if ( timer_list == NULL ) { result = 0; } else { result = (timer_list->when) - time(NULL); } if ( result < 0 ) { result = 0; } return(result); } dprintf( D_DAEMONCORE, "In DaemonCore Timeout()\n"); if (timer_list == NULL) { dprintf( D_DAEMONCORE, "Empty timer list, nothing to do\n" ); } time(&now); timer_check_cntr = 0; DumpTimerList(D_DAEMONCORE | D_FULLDEBUG); // loop until all handlers that should have been called by now or before // are invoked and renewed if periodic. Remember that NewTimer and CancelTimer // keep the timer_list happily sorted on "when" for us. We use "now" as a // variable so that if some of these handler functions run for a long time, // we do not sit in this loop forever. // we make certain we do not call more than "max_fires" handlers in a // single timeout --- this ensures that timers don't starve out the rest // of daemonCore if a timer handler resets itself to 0. while( (timer_list != NULL) && (timer_list->when <= now ) && (num_fires++ < MAX_FIRES_PER_TIMEOUT)) { // DumpTimerList(D_DAEMONCORE | D_FULLDEBUG); in_timeout = timer_list; // In some cases, resuming from a suspend can cause the system // clock to become temporarily skewed, causing crazy things to // happen with our timers (particularly for sending updates to // the collector). So, to correct for such skews, we routinely // check to make sure that 'now' is not in the future. timer_check_cntr++; // since time() is somewhat expensive, we // only check every 10 times we loop if ( timer_check_cntr > 10 ) { timer_check_cntr = 0; time(&time_sample); if (now > time_sample) { dprintf(D_ALWAYS, "DaemonCore: Clock skew detected " "(time=%ld; now=%ld). Resetting TimerManager's " "notion of 'now'\n", (long) time_sample, (long) now); now = time_sample; } } // Update curr_dataptr for GetDataPtr() curr_dataptr = &(in_timeout->data_ptr); // Initialize our flag so we know if ResetTimer was called. did_reset = false; did_cancel = false; // Log a message before calling handler, but only if // D_FULLDEBUG is also enabled. if (IsDebugVerbose(D_COMMAND)) { dprintf(D_COMMAND, "Calling Timer handler %d (%s)\n", in_timeout->id, in_timeout->event_descrip); } if( in_timeout->timeslice ) { in_timeout->timeslice->setStartTimeNow(); } // Now we call the registered handler. If we were told that the handler // is a c++ method, we call the handler from the c++ object referenced // by service*. If we were told the handler is a c function, we call // it and pass the service* as a parameter. if ( in_timeout->handlercpp ) { // typedef int (*TimerHandlercpp)() ((in_timeout->service)->*(in_timeout->handlercpp))(); } else { // typedef int (*TimerHandler)() (*(in_timeout->handler))(); } if( in_timeout->timeslice ) { in_timeout->timeslice->setFinishTimeNow(); } if (IsDebugVerbose(D_COMMAND)) { if( in_timeout->timeslice ) { dprintf(D_COMMAND, "Return from Timer handler %d (%s) - took %.3fs\n", in_timeout->id, in_timeout->event_descrip, in_timeout->timeslice->getLastDuration() ); } else { dprintf(D_COMMAND, "Return from Timer handler %d (%s)\n", in_timeout->id, in_timeout->event_descrip); } } if (pruntime) { *pruntime = daemonCore->dc_stats.AddRuntime(in_timeout->event_descrip, *pruntime); } // Make sure we didn't leak our priv state daemonCore->CheckPrivState(); // Clear curr_dataptr curr_dataptr = NULL; if ( did_cancel ) { // Timer was canceled inside its handler. All we need to do // is delete it. DeleteTimer( in_timeout ); } else if ( !did_reset ) { // here we remove the timer we just serviced, or renew it if it is // periodic. // If a new timer was added at a time in the past // (possible when resetting a timeslice timer), then // it may have landed before the timer we just processed, // meaning that we cannot assume prev==NULL in the call // to RemoveTimer() below. Timer *prev = NULL; ASSERT( GetTimer(in_timeout->id,&prev) == in_timeout ); RemoveTimer( in_timeout, prev ); if ( in_timeout->period > 0 || in_timeout->timeslice ) { in_timeout->period_started = time(NULL); in_timeout->when = in_timeout->period_started; if ( in_timeout->timeslice ) { in_timeout->when += in_timeout->timeslice->getTimeToNextRun(); } else { if( in_timeout->period == TIMER_NEVER ) { in_timeout->when = TIME_T_NEVER; } else { in_timeout->when += in_timeout->period; } } InsertTimer( in_timeout ); } else { // timer is not perodic; it is just a one-time event. we just called // the handler, so now just delete it. DeleteTimer( in_timeout ); } } } // end of while loop // set result to number of seconds until next event. get an update on the // time from time() in case the handlers we called above took significant time. if ( timer_list == NULL ) { // we set result to be -1 so that we do not busy poll. // a -1 return value will tell the DaemonCore:Driver to use select with // no timeout. result = -1; } else { result = (timer_list->when) - time(NULL); if (result < 0) result = 0; } dprintf( D_DAEMONCORE, "DaemonCore Timeout() Complete, returning %d \n",result); if (pNumFired) *pNumFired = num_fires; in_timeout = NULL; return(result); }
int TimerManager::ResetTimer(int id, unsigned when, unsigned period, bool recompute_when, Timeslice const *new_timeslice) { Timer* timer_ptr; Timer* trail_ptr; dprintf( D_DAEMONCORE, "In reset_timer(), id=%d, time=%d, period=%d\n",id,when,period); if (timer_list == NULL) { dprintf( D_DAEMONCORE, "Reseting Timer from empty list!\n"); return -1; } timer_ptr = timer_list; trail_ptr = NULL; while ( timer_ptr && timer_ptr->id != id ) { trail_ptr = timer_ptr; timer_ptr = timer_ptr->next; } if ( timer_ptr == NULL ) { dprintf( D_ALWAYS, "Timer %d not found\n",id ); return -1; } if ( new_timeslice ) { if( timer_ptr->timeslice == NULL ) { timer_ptr->timeslice = new Timeslice( *new_timeslice ); } else { *timer_ptr->timeslice = *new_timeslice; } timer_ptr->when = timer_ptr->timeslice->getNextStartTime(); } else if ( timer_ptr->timeslice ) { dprintf( D_DAEMONCORE, "Timer %d with timeslice can't be reset\n", id ); return 0; } else if( recompute_when ) { time_t old_when = timer_ptr->when; timer_ptr->when = timer_ptr->period_started + period; // sanity check int wait_time = (int)timer_ptr->when - (int)time(NULL); if( wait_time > (int64_t)period ) { dprintf(D_ALWAYS, "ResetTimer() tried to set next call to %d (%s) %ds into" " the future, which is larger than the new period %d.\n", id, timer_ptr->event_descrip ? timer_ptr->event_descrip : "", wait_time, period); // start a new period now to restore sanity timer_ptr->period_started = time(NULL); timer_ptr->when = timer_ptr->period_started + period; } dprintf(D_FULLDEBUG, "Changing period of timer %d (%s) from %u to %u " "(added %ds to time of next scheduled call)\n", id, timer_ptr->event_descrip ? timer_ptr->event_descrip : "", timer_ptr->period, period, (int)timer_ptr->when - (int)old_when); } else { timer_ptr->period_started = time(NULL); if ( when == TIMER_NEVER ) { timer_ptr->when = TIME_T_NEVER; } else { timer_ptr->when = when + timer_ptr->period_started; } } timer_ptr->period = period; RemoveTimer( timer_ptr, trail_ptr ); InsertTimer( timer_ptr ); if ( in_timeout == timer_ptr ) { // We're inside the handler for this timer. Let Timeout() know // the timer has already been reset for its next call. did_reset = true; } return 0; }
// Add a new event in the timer list. if period is 0, this event is a one time // event instead of periodical int TimerManager::NewTimer(Service* s, unsigned deltawhen, TimerHandler handler, TimerHandlercpp handlercpp, Release release, Releasecpp releasecpp, const char *event_descrip, unsigned period, const Timeslice *timeslice) { Timer* new_timer; dprintf( D_DAEMONCORE, "in DaemonCore NewTimer()\n" ); new_timer = new Timer; if ( new_timer == NULL ) { dprintf( D_ALWAYS, "DaemonCore: Unable to allocate new timer\n" ); return -1; } if (daemonCore) { daemonCore->dc_stats.NewProbe("Timer", event_descrip, AS_COUNT | IS_RCT | IF_NONZERO | IF_VERBOSEPUB); } new_timer->handler = handler; new_timer->handlercpp = handlercpp; new_timer->release = release; new_timer->releasecpp = releasecpp; new_timer->period = period; new_timer->service = s; if( timeslice ) { new_timer->timeslice = new Timeslice( *timeslice ); deltawhen = new_timer->timeslice->getTimeToNextRun(); } else { new_timer->timeslice = NULL; } new_timer->period_started = time(NULL); if ( TIMER_NEVER == deltawhen ) { new_timer->when = TIME_T_NEVER; } else { new_timer->when = deltawhen + new_timer->period_started; } new_timer->data_ptr = NULL; if ( event_descrip ) new_timer->event_descrip = strdup(event_descrip); else new_timer->event_descrip = strdup("<NULL>"); new_timer->id = timer_ids++; InsertTimer( new_timer ); DumpTimerList(D_DAEMONCORE | D_FULLDEBUG); // Update curr_regdataptr for SetDataPtr() curr_regdataptr = &(new_timer->data_ptr); dprintf(D_DAEMONCORE,"leaving DaemonCore NewTimer, id=%d\n",new_timer->id); return new_timer->id; }