diff --git a/documentation/new-notes/PR-744.md b/documentation/new-notes/PR-744.md new file mode 100644 index 000000000..27dcbfadd --- /dev/null +++ b/documentation/new-notes/PR-744.md @@ -0,0 +1,12 @@ +### Avoid early expiration of timers on non-RTOS + +Previously, the epicsTimer code rounded down user requested delays by subtracting one half +of the sleep "quantum". +On RTEMS and vxWorks, this allowed periodic timers which expired on every tick. +However, this also resulted in +timers expiring slightly [earlier than requested](https://github.com/epics-base/epics-base/issues/106). + +With [PR 744](https://github.com/epics-base/epics-base/pull/744) +rounding is only done for RTEMS and vxWorks, which still have tick timers. + +This effects several facilities which use epicsTimer, including record delays. eg. `calcout.ODLY` becomes more [accurate](https://github.com/epics-base/epics-base/issues/106#issuecomment-1260232765). diff --git a/modules/libcom/src/timer/timer.cpp b/modules/libcom/src/timer/timer.cpp index 679ca27ef..f7da1c476 100644 --- a/modules/libcom/src/timer/timer.cpp +++ b/modules/libcom/src/timer/timer.cpp @@ -65,7 +65,11 @@ void timer::start ( epicsTimerNotify & notify, const epicsTime & expire ) void timer::privateStart ( epicsTimerNotify & notify, const epicsTime & expire ) { this->pNotify = & notify; - this->exp = expire - ( this->queue.notify.quantum () / 2.0 ); + this->exp = expire +#ifdef TIMER_QUANTUM_BIAS + - ( this->queue.notify.quantum () / 2.0 ) +#endif + ; bool reschedualNeeded = false; if ( this->curState == stateActive ) { diff --git a/modules/libcom/src/timer/timerPrivate.h b/modules/libcom/src/timer/timerPrivate.h index eea26808f..f221ee54c 100644 --- a/modules/libcom/src/timer/timerPrivate.h +++ b/modules/libcom/src/timer/timerPrivate.h @@ -35,6 +35,16 @@ # define debugPrintf(ARGSINPAREN) #endif +/* For historical reasons, round down expiration time on vxWorks and RTEMS. + * Targets with a fixed timer period. + * This biasing down by half a period allows timers which expire on every tick. + * Otherwise, the fastest timer is 2x the tick period. + * This results in timers expiring one period earlier than requested. + */ +#if defined(vxWorks) || defined(__rtems__) +# define TIMER_QUANTUM_BIAS 1 +#endif + template < class T > class epicsGuard; class timer : public epicsTimer, public tsDLNode < timer > { diff --git a/modules/libcom/test/Makefile b/modules/libcom/test/Makefile index a19a9bac0..8c3da6928 100644 --- a/modules/libcom/test/Makefile +++ b/modules/libcom/test/Makefile @@ -10,6 +10,9 @@ TOP = ../../.. include $(TOP)/configure/CONFIG +# allow tests to peek at private headers +USR_CPPFLAGS += -I$(TOP)/modules/libcom/src + PROD_LIBS += Com PROD_SYS_LIBS_WIN32 += ws2_32 advapi32 user32 PROD_SYS_LIBS_solaris += socket nsl