diff --git a/include/znc/Csocket.h b/include/znc/Csocket.h index 1bbd88e4..83f905fc 100644 --- a/include/znc/Csocket.h +++ b/include/znc/Csocket.h @@ -362,16 +362,18 @@ public: virtual ~CCron() {} //! This is used by the Job Manager, and not you directly - void run( time_t & iNow ); + void run( timeval & tNow ); /** * @param TimeSequence how often to run in seconds * @param iMaxCycles how many times to run, 0 makes it run forever */ - void StartMaxCycles( int TimeSequence, u_int iMaxCycles ); + void StartMaxCycles( double fTimeSequence, u_int iMaxCycles ); + void StartMaxCycles( const timeval& tTimeSequence, u_int iMaxCycles ); //! starts and runs infinity amount of times - void Start( int TimeSequence ); + void Start( double fTimeSequence ); + void Start( const timeval& TimeSequence ); //! call this to turn off your cron, it will be removed void Stop(); @@ -382,7 +384,7 @@ public: //! removes the pause on RunJon void UnPause(); - int GetInterval() const; + timeval GetInterval() const; u_int GetMaxCycles() const; u_int GetCyclesLeft() const; @@ -393,7 +395,7 @@ public: void SetName( const CS_STRING & sName ); //! returns the timestamp of the next estimated run time. Note that it may not run at this EXACT time, but it will run at least at this time or after - time_t GetNextRun() const { return( m_iTime ); } + timeval GetNextRun() const { return( m_tTime ); } public: @@ -404,9 +406,9 @@ protected: bool m_bRunOnNextCall; //!< if set to true, RunJob() gets called on next invocation of run() despite the timeout private: - time_t m_iTime; + timeval m_tTime; bool m_bActive, m_bPause; - int m_iTimeSequence; + timeval m_tTimeSequence; u_int m_iMaxCycles, m_iCycles; CS_STRING m_sName; }; @@ -1494,7 +1496,7 @@ private: */ void Select( std::map & mpeSocks ); - time_t GetDynamicSleepTime( time_t iNow, time_t iMaxResolution = 3600 ) const; + timeval GetDynamicSleepTime( const timeval& tNow, const timeval& tMaxResolution ) const; //! internal use only virtual void SelectSock( std::map & mpeSocks, EMessages eErrno, Csock * pcSock ); diff --git a/src/Csocket.cpp b/src/Csocket.cpp index 23b23b8f..01cd256e 100644 --- a/src/Csocket.cpp +++ b/src/Csocket.cpp @@ -627,21 +627,22 @@ CCron::CCron() m_iCycles = 0; m_iMaxCycles = 0; m_bActive = true; - m_iTime = 0; - m_iTimeSequence = 60; + timerclear( &m_tTime ); + m_tTimeSequence.tv_sec = 60; + m_tTimeSequence.tv_usec = 0; m_bPause = false; m_bRunOnNextCall = false; } -void CCron::run( time_t & iNow ) +void CCron::run( timeval & tNow ) { if( m_bPause ) return; - if( iNow == 0 ) - iNow = time( NULL ); + if( !timerisset( &tNow ) ) + gettimeofday( &tNow, NULL ); - if(( m_bActive ) && ( iNow >= m_iTime || m_bRunOnNextCall ) ) + if(( m_bActive ) && ( !timercmp( &tNow, &m_tTime, < ) || m_bRunOnNextCall ) ) { m_bRunOnNextCall = false; // Setting this here because RunJob() could set it back to true RunJob(); @@ -649,22 +650,37 @@ void CCron::run( time_t & iNow ) if(( m_iMaxCycles > 0 ) && ( ++m_iCycles >= m_iMaxCycles ) ) m_bActive = false; else - m_iTime = iNow + m_iTimeSequence; + timeradd( &tNow, &m_tTimeSequence, &m_tTime ); } } -void CCron::StartMaxCycles( int TimeSequence, u_int iMaxCycles ) +void CCron::StartMaxCycles( double fTimeSequence, u_int iMaxCycles ) { - m_iTimeSequence = TimeSequence; - m_iTime = time( NULL ) + m_iTimeSequence; + timeval tNow; + m_tTimeSequence.tv_sec = (time_t) fTimeSequence; + m_tTimeSequence.tv_usec = (suseconds_t) ((fTimeSequence - (time_t) fTimeSequence) * 1000000); + gettimeofday( &tNow, NULL ); + timeradd( &tNow, &m_tTimeSequence, &m_tTime ); m_iMaxCycles = iMaxCycles; } -void CCron::Start( int TimeSequence ) +void CCron::StartMaxCycles( const timeval& tTimeSequence, u_int iMaxCycles ) { - m_iTimeSequence = TimeSequence; - m_iTime = time( NULL ) + m_iTimeSequence; - m_iMaxCycles = 0; + timeval tNow; + m_tTimeSequence = tTimeSequence; + gettimeofday( &tNow, NULL ); + timeradd( &tNow, &m_tTimeSequence, &m_tTime ); + m_iMaxCycles = iMaxCycles; +} + +void CCron::Start( double fTimeSequence ) +{ + StartMaxCycles( fTimeSequence, 0 ); +} + +void CCron::Start( const timeval& tTimeSequence ) +{ + StartMaxCycles( tTimeSequence, 0 ); } void CCron::Stop() @@ -682,7 +698,7 @@ void CCron::UnPause() m_bPause = false; } -int CCron::GetInterval() const { return( m_iTimeSequence ); } +timeval CCron::GetInterval() const { return( m_tTimeSequence ); } u_int CCron::GetMaxCycles() const { return( m_iMaxCycles ); } u_int CCron::GetCyclesLeft() const { return(( m_iMaxCycles > m_iCycles ? ( m_iMaxCycles - m_iCycles ) : 0 ) ); } @@ -765,7 +781,8 @@ void CSockCommon::AssignFDs( std::map< int, short > & miiReadyFds, struct timeva void CSockCommon::Cron() { - time_t iNow = 0; + timeval tNow; + timerclear( &tNow ); for( vector::size_type a = 0; a < m_vcCrons.size(); a++ ) { @@ -777,7 +794,7 @@ void CSockCommon::Cron() m_vcCrons.erase( m_vcCrons.begin() + a-- ); } else - pcCron->run( iNow ); + pcCron->run( tNow ); } } @@ -2893,9 +2910,13 @@ void CSocketManager::DynamicSelectLoop( u_long iLowerBounds, u_long iUpperBounds if( m_errno == SELECT_TIMEOUT ) { // only do this if the previous call to select was a timeout - time_t iNow = time( NULL ); - u_long iSelectTimeout = GetDynamicSleepTime( iNow, iMaxResolution ); - iSelectTimeout *= 1000000; + timeval tMaxResolution; + timeval tNow; + tMaxResolution.tv_sec = iMaxResolution; + tMaxResolution.tv_usec = 0; + gettimeofday( &tNow, NULL ); + timeval tSelectTimeout = GetDynamicSleepTime( tNow, tMaxResolution ); + u_long iSelectTimeout = tSelectTimeout.tv_sec * 1000000 + tSelectTimeout.tv_usec; iSelectTimeout = std::max( iLowerBounds, iSelectTimeout ); iSelectTimeout = std::min( iSelectTimeout, iUpperBounds ); if( iLowerBounds != iSelectTimeout ) @@ -3478,9 +3499,18 @@ void CSocketManager::Select( std::map & mpeSocks ) } } -time_t CSocketManager::GetDynamicSleepTime( time_t iNow, time_t iMaxResolution ) const +inline void MinimizeTime( timeval& min, const timeval& another ) { - time_t iNextRunTime = iNow + iMaxResolution; + if( timercmp( &min, &another, > ) ) + { + min = another; + } +} + +timeval CSocketManager::GetDynamicSleepTime( const timeval& tNow, const timeval& tMaxResolution ) const +{ + timeval tNextRunTime; + timeradd( &tNow, &tMaxResolution, &tNextRunTime ); std::vector::const_iterator it; // This is safe, because we don't modify the vector. std::vector::const_iterator it_end = this->end(); @@ -3490,29 +3520,37 @@ time_t CSocketManager::GetDynamicSleepTime( time_t iNow, time_t iMaxResolution ) Csock* pSock = *it; if( pSock->GetConState() != Csock::CST_OK ) - iNextRunTime = iNow; // this is in a nebulous state, need to let it proceed like normal + tNextRunTime = tNow; // this is in a nebulous state, need to let it proceed like normal time_t iTimeoutInSeconds = pSock->GetTimeout(); if( iTimeoutInSeconds > 0 ) { - time_t iNextTimeout = pSock->GetNextCheckTimeout( iNow ); - iNextRunTime = std::min( iNextRunTime, iNextTimeout ); + timeval tNextTimeout; + tNextTimeout.tv_sec = pSock->GetNextCheckTimeout( 0 ); // TODO convert socket timeouts to timeval too? + tNextTimeout.tv_usec = 0; + MinimizeTime( tNextRunTime, tNextTimeout ); } const std::vector & vCrons = pSock->GetCrons(); std::vector::const_iterator cit; std::vector::const_iterator cit_end = vCrons.end(); for( cit = vCrons.begin(); cit != cit_end; cit++ ) - iNextRunTime = std::min( iNextRunTime, ( *cit )->GetNextRun() ); + MinimizeTime( tNextRunTime, ( *cit )->GetNextRun() ); } std::vector::const_iterator cit; std::vector::const_iterator cit_end = m_vcCrons.end(); for( cit = m_vcCrons.begin(); cit != cit_end; cit++ ) - iNextRunTime = std::min( iNextRunTime, ( *cit )->GetNextRun() ); + MinimizeTime( tNextRunTime, ( *cit )->GetNextRun() ); - if( iNextRunTime < iNow ) - return( 0 ); // smallest unit possible - return( std::min( iNextRunTime - iNow, iMaxResolution ) ); + timeval tReturnValue; + if( timercmp( &tNextRunTime, &tNow, < ) ) + { + timerclear( &tReturnValue ); + return( tReturnValue ); // smallest unit possible + } + timersub( &tNextRunTime, &tNow, &tReturnValue ); + MinimizeTime( tReturnValue, tMaxResolution ); + return( tReturnValue ); } void CSocketManager::SelectSock( std::map & mpeSocks, EMessages eErrno, Csock * pcSock ) diff --git a/src/Modules.cpp b/src/Modules.cpp index acae8385..8d79eca2 100644 --- a/src/Modules.cpp +++ b/src/Modules.cpp @@ -303,10 +303,11 @@ void CModule::ListTimers() { for (it = m_sTimers.begin(); it != m_sTimers.end(); ++it) { CTimer* pTimer = *it; unsigned int uCycles = pTimer->GetCyclesLeft(); + timeval Interval = pTimer->GetInterval(); Table.AddRow(); Table.SetCell("Name", pTimer->GetName()); - Table.SetCell("Secs", CString(pTimer->GetInterval())); + Table.SetCell("Secs", CString(Interval.tv_sec) + "seconds" + (Interval.tv_usec ? " " + CString(Interval.tv_usec) + " microseconds" : "")); Table.SetCell("Cycles", ((uCycles) ? CString(uCycles) : "INF")); Table.SetCell("Description", pTimer->GetDescription()); }