/*************************************************************************\ * Copyright (c) 2015 UChicago Argonne LLC, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * SPDX-License-Identifier: EPICS * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ /* * Author Jeffrey O. Hill * johill@lanl.gov * 505 665 1831 */ #include #include "epicsAtomic.h" #include "timerPrivate.h" #include "errlog.h" #ifdef _MSC_VER # pragma warning ( push ) # pragma warning ( disable:4660 ) #endif template class epicsSingleton < timerQueueActiveMgr >; #ifdef _MSC_VER # pragma warning ( pop ) #endif epicsSingleton < timerQueueActiveMgr > timerQueueMgrEPICS; epicsTimerQueueActive::~epicsTimerQueueActive () {} epicsTimerQueueActive & epicsTimerQueueActive::allocate ( bool okToShare, unsigned threadPriority ) { epicsSingleton < timerQueueActiveMgr >::reference pMgr = timerQueueMgrEPICS.getReference (); return pMgr->allocate ( pMgr, okToShare, threadPriority ); } timerQueueActive :: timerQueueActive ( RefMgr & refMgr, bool okToShareIn, unsigned priority ) : _refMgr ( refMgr ), queue ( *this ), thread ( *this, "timerQueue", epicsThreadGetStackSize ( epicsThreadStackMedium ), priority ), sleepQuantum ( epicsThreadSleepQuantum() ), okToShare ( okToShareIn ), exitFlag ( 0 ), terminateFlag ( false ) { } void timerQueueActive::start () { this->thread.start (); } timerQueueActive::~timerQueueActive () { this->terminateFlag = true; this->rescheduleEvent.signal (); while ( ! epics::atomic::get(this->exitFlag) ) { this->exitEvent.wait ( 1.0 ); } // in case other threads are waiting here also this->exitEvent.signal (); } void timerQueueActive :: _printLastChanceExceptionMessage ( const char * pExceptionTypeName, const char * pExceptionContext ) { char date[64]; try { epicsTime cur = epicsTime :: getCurrent (); cur.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f"); } catch ( ... ) { strcpy ( date, "" ); } errlogPrintf ( "timerQueueActive: Unexpected C++ exception \"%s\" with type \"%s\" " "while processing timer queue, at %s\n", pExceptionContext, pExceptionTypeName, date ); } void timerQueueActive :: run () { epics::atomic::set(this->exitFlag, 0); while ( ! this->terminateFlag ) { try { double delay = this->queue.process ( epicsTime::getCurrent() ); debugPrintf ( ( "timer thread sleeping for %g sec (max)\n", delay ) ); this->rescheduleEvent.wait ( delay ); } catch ( std :: exception & except ) { _printLastChanceExceptionMessage ( typeid ( except ).name (), except.what () ); epicsThreadSleep ( 10.0 ); } catch ( ... ) { _printLastChanceExceptionMessage ( "catch ( ... )", "Non-standard C++ exception" ); epicsThreadSleep ( 10.0 ); } } epics::atomic::set(this->exitFlag, 1); this->exitEvent.signal (); // no access to queue after exitEvent signal } epicsTimer & timerQueueActive::createTimer () { return this->queue.createTimer(); } epicsTimerForC & timerQueueActive::createTimerForC ( epicsTimerCallback pCallback, void * pArg ) { return this->queue.createTimerForC ( pCallback, pArg ); } void timerQueueActive::reschedule () { this->rescheduleEvent.signal (); } double timerQueueActive::quantum () { return this->sleepQuantum; } void timerQueueActive::show ( unsigned int level ) const { printf ( "EPICS threaded timer queue at %p\n", static_cast ( this ) ); if ( level > 0u ) { // specifying level one here avoids recursive // show callback this->thread.show ( 1u ); this->queue.show ( level - 1u ); printf ( "reschedule event\n" ); this->rescheduleEvent.show ( level - 1u ); printf ( "exit event\n" ); this->exitEvent.show ( level - 1u ); printf ( "exitFlag = %c, terminateFlag = %c\n", epics::atomic::get(this->exitFlag) ? 'T' : 'F', this->terminateFlag ? 'T' : 'F' ); } } epicsTimerQueue & timerQueueActive::getEpicsTimerQueue () { return static_cast < epicsTimerQueue &> ( * this ); }