18922761a6
Signed-off-by: Dean Troyer <dtroyer@gmail.com>
605 lines
16 KiB
C++
Executable File
605 lines
16 KiB
C++
Executable File
/*
|
|
* Copyright (c) 2013, 2016 Wind River Systems, Inc.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* Wind River CGTS Platform Node Maintenance "Timer Facility"
|
|
* Implementation
|
|
*/
|
|
|
|
/**
|
|
* @detail
|
|
* Detailed description ...
|
|
*
|
|
* Common timer struct
|
|
*
|
|
*/
|
|
|
|
#include "daemon_common.h"
|
|
#include "nodeBase.h"
|
|
#include "nodeTimers.h"
|
|
|
|
static int timer_count = 0 ;
|
|
|
|
int _timer_start ( struct mtc_timer * mtcTimer_ptr,
|
|
void (*handler)(int, siginfo_t*, void*),
|
|
int secs, int msec )
|
|
|
|
{
|
|
int rc = PASS ;
|
|
|
|
if ( mtcTimer_ptr == NULL)
|
|
{
|
|
return (FAIL_NULL_POINTER);
|
|
}
|
|
|
|
mtcTimer_ptr->mutex = true ;
|
|
mtcTimer_ptr->ring = true ; /* default to rung for failure path cases */
|
|
|
|
/* Avoid programming mistake that leads to over-writing
|
|
* a seemingly active timer; if .tid is not null then
|
|
* cancel that timr first */
|
|
if (( mtcTimer_ptr->tid ) && ( timer_count > 0 ))
|
|
{
|
|
wlog ("%s (%s) called with active timer ; stopping first \n",
|
|
mtcTimer_ptr->hostname.c_str(),
|
|
mtcTimer_ptr->service.c_str());
|
|
mtcTimer_stop ( mtcTimer_ptr );
|
|
}
|
|
|
|
if (( handler == NULL ) ||
|
|
(( secs == 0 ) && ( msec == 0 )) ||
|
|
( secs > MAX_TIMER_DURATION ))
|
|
{
|
|
elog ("%s (%s) Invalid Duration (%d:%d)\n",
|
|
mtcTimer_ptr->hostname.c_str(),
|
|
mtcTimer_ptr->service.c_str(),
|
|
secs, msec );
|
|
|
|
rc = FAIL_BAD_PARM ;
|
|
goto _timer_start_out ;
|
|
}
|
|
|
|
/* Clean the timer struct */
|
|
memset ( &mtcTimer_ptr->sev, 0, sizeof(struct sigevent));
|
|
memset ( &mtcTimer_ptr->value, 0, sizeof(struct itimerspec));
|
|
memset ( &mtcTimer_ptr->sa, 0, sizeof(struct sigaction));
|
|
|
|
/* Setup the timer */
|
|
mtcTimer_ptr->sa.sa_flags = SA_SIGINFO;
|
|
mtcTimer_ptr->sa.sa_sigaction = handler;
|
|
sigemptyset(&mtcTimer_ptr->sa.sa_mask);
|
|
if (sigaction(SIGRTMIN, &mtcTimer_ptr->sa, NULL) == -1)
|
|
{
|
|
elog ("%s (%s) Timer 'set action' (sigaction) failed\n",
|
|
mtcTimer_ptr->hostname.c_str(),
|
|
mtcTimer_ptr->service.c_str());
|
|
|
|
rc = FAIL_TIMER_SET_ACTION ;
|
|
goto _timer_start_out ;
|
|
|
|
}
|
|
/* set and enable alarm */
|
|
mtcTimer_ptr->sev.sigev_notify = SIGEV_SIGNAL;
|
|
mtcTimer_ptr->sev.sigev_signo = SIGRTMIN;
|
|
mtcTimer_ptr->sev.sigev_value.sival_ptr = &mtcTimer_ptr->tid;
|
|
|
|
/* TODO: move up or set block till time is set ? */
|
|
mtcTimer_ptr->value.it_value.tv_sec = secs;
|
|
mtcTimer_ptr->value.it_value.tv_nsec = (msec*1000000) ;
|
|
mtcTimer_ptr->value.it_interval.tv_sec = secs ;
|
|
mtcTimer_ptr->value.it_interval.tv_nsec = (msec*1000000) ;
|
|
|
|
if ( timer_create (CLOCK_REALTIME, &mtcTimer_ptr->sev, &mtcTimer_ptr->tid) == -1 )
|
|
{
|
|
elog ("%s (%s) Timer 'create' (timer_create) failed (-1)\n",
|
|
mtcTimer_ptr->hostname.c_str(),
|
|
mtcTimer_ptr->service.c_str() );
|
|
|
|
rc = FAIL_TIMER_CREATE ;
|
|
goto _timer_start_out ;
|
|
}
|
|
|
|
/* make a backup copy just for fun */
|
|
mtcTimer_ptr->secs = secs ;
|
|
mtcTimer_ptr->msec = msec ;
|
|
timer_count++ ;
|
|
|
|
/* Set the ring to false DEFORE we start the timer */
|
|
mtcTimer_ptr->_guard = 0x12345678 ;
|
|
mtcTimer_ptr->guard_ = 0x77654321 ;
|
|
mtcTimer_ptr->ring = false ;
|
|
|
|
if ( timer_settime (mtcTimer_ptr->tid, 0, &mtcTimer_ptr->value, NULL) == -1 )
|
|
{
|
|
elog ("%s (%s) Timer 'set time' (timer_settime) failed (-1)\n",
|
|
mtcTimer_ptr->hostname.c_str(),
|
|
mtcTimer_ptr->service.c_str() );
|
|
|
|
timer_count-- ;
|
|
rc = FAIL_TIMER_SET ;
|
|
goto _timer_start_out ;
|
|
}
|
|
mtcTimer_ptr->active = true ;
|
|
|
|
/* moved here so that the tid will be valid in the log for debug purposes */
|
|
tlog ("%s (%s) Tid:%p with %d.%03d second timeout (count:%d)\n",
|
|
mtcTimer_ptr->hostname.c_str(),
|
|
mtcTimer_ptr->service.c_str(),
|
|
mtcTimer_ptr->tid,
|
|
mtcTimer_ptr->secs,
|
|
mtcTimer_ptr->msec,
|
|
timer_count );
|
|
|
|
_timer_start_out:
|
|
|
|
mtcTimer_ptr->mutex = false ;
|
|
|
|
return rc ;
|
|
}
|
|
|
|
int mtcTimer_start ( struct mtc_timer & mtcTimer,
|
|
void (*handler)(int, siginfo_t*, void*),
|
|
int secs )
|
|
{
|
|
return ( _timer_start ( &mtcTimer, handler, secs, 0 ));
|
|
}
|
|
|
|
int mtcTimer_start_msec ( struct mtc_timer & mtcTimer,
|
|
void (*handler)(int, siginfo_t*, void*),
|
|
int msec )
|
|
{
|
|
return ( _timer_start ( &mtcTimer, handler, 0, msec ));
|
|
}
|
|
|
|
int mtcTimer_start ( struct mtc_timer * mtcTimer_ptr,
|
|
void (*handler)(int, siginfo_t*, void*),
|
|
int secs )
|
|
{
|
|
return ( _timer_start ( mtcTimer_ptr, handler, secs, 0 ));
|
|
}
|
|
|
|
int mtcTimer_start_sec_msec ( struct mtc_timer * mtcTimer_ptr,
|
|
void (*handler)(int, siginfo_t*, void*),
|
|
int secs , int msec )
|
|
{
|
|
return ( _timer_start ( mtcTimer_ptr, handler, secs, msec ));
|
|
}
|
|
|
|
int mtcTimer_start_msec ( struct mtc_timer * mtcTimer_ptr,
|
|
void (*handler)(int, siginfo_t*, void*),
|
|
int msec )
|
|
{
|
|
return ( _timer_start ( mtcTimer_ptr, handler, 0, msec ));
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
int _timer_stop ( struct mtc_timer * mtcTimer_ptr , bool int_safe)
|
|
{
|
|
int rc = PASS ;
|
|
|
|
if ( mtcTimer_ptr == NULL)
|
|
{
|
|
return (FAIL_NULL_POINTER);
|
|
}
|
|
|
|
if ( timer_count == 0 )
|
|
{
|
|
if ( int_safe == false )
|
|
{
|
|
elog ("%s (%s) called with no outstanding timers\n",
|
|
mtcTimer_ptr->hostname.c_str(),
|
|
mtcTimer_ptr->service.c_str());
|
|
}
|
|
goto _timer_stop_out ;
|
|
}
|
|
else if ( mtcTimer_ptr->tid )
|
|
{
|
|
mtcTimer_ptr->value.it_value.tv_sec = 0;
|
|
mtcTimer_ptr->value.it_value.tv_nsec = 0;
|
|
mtcTimer_ptr->value.it_interval.tv_sec = 0;
|
|
mtcTimer_ptr->value.it_interval.tv_nsec = 0;
|
|
if ( timer_settime (mtcTimer_ptr->tid, 0, &mtcTimer_ptr->value, NULL) == -1 )
|
|
{
|
|
if ( int_safe == false )
|
|
{
|
|
elog ("%s (%s) timer_settime failed (tid:%p)\n",
|
|
mtcTimer_ptr->hostname.c_str(),
|
|
mtcTimer_ptr->service.c_str(),
|
|
mtcTimer_ptr->tid );
|
|
}
|
|
rc = FAIL_TIMER_STOP ;
|
|
goto _timer_stop_out ;
|
|
}
|
|
|
|
if ( int_safe == false )
|
|
{
|
|
tlog ("%s (%s) Tid:%p with %d.%d second timeout (count:%d)\n",
|
|
mtcTimer_ptr->hostname.c_str(),
|
|
mtcTimer_ptr->service.c_str(),
|
|
mtcTimer_ptr->tid,
|
|
mtcTimer_ptr->secs,
|
|
mtcTimer_ptr->msec,
|
|
timer_count );
|
|
}
|
|
timer_delete (mtcTimer_ptr->tid);
|
|
mtcTimer_ptr->tid = NULL ;
|
|
if ( timer_count )
|
|
timer_count-- ;
|
|
}
|
|
else if ( int_safe == false )
|
|
{
|
|
elog ("%s (%s) called with null TID (count:%d)\n",
|
|
mtcTimer_ptr->hostname.c_str(),
|
|
mtcTimer_ptr->service.c_str(),
|
|
timer_count);
|
|
}
|
|
|
|
#ifdef WANT_OUTSTANDING_TIMER_COUNT
|
|
if ( int_safe == false )
|
|
{
|
|
tlog ("%s (%s) Outstanding timers: %d\n",
|
|
mtcTimer_ptr->hostname.c_str(),
|
|
mtcTimer_ptr->service.c_str(),
|
|
timer_count );
|
|
}
|
|
#endif
|
|
|
|
_timer_stop_out:
|
|
mtcTimer_ptr->active = false ;
|
|
return rc ;
|
|
}
|
|
|
|
|
|
/* Interrupt level safe timer stop utility by pointer */
|
|
int mtcTimer_stop_int_safe ( struct mtc_timer * mtcTimer_ptr )
|
|
{
|
|
return ( _timer_stop ( mtcTimer_ptr, true )) ;
|
|
}
|
|
|
|
/* Interrupt level safe timer stop utility by reference */
|
|
int mtcTimer_stop_int_safe ( struct mtc_timer & mtcTimer )
|
|
{
|
|
return ( _timer_stop ( &mtcTimer, true ) );
|
|
}
|
|
|
|
/* timer stop utility by pointer */
|
|
int mtcTimer_stop ( struct mtc_timer * mtcTimer_ptr )
|
|
{
|
|
return ( _timer_stop ( mtcTimer_ptr, false ) );
|
|
}
|
|
|
|
/* stop utility by reference */
|
|
int mtcTimer_stop ( struct mtc_timer & mtcTimer )
|
|
{
|
|
return ( _timer_stop ( &mtcTimer , false ));
|
|
}
|
|
|
|
|
|
|
|
bool mtcTimer_expired ( struct mtc_timer & mtcTimer )
|
|
{
|
|
if (( mtcTimer.ring == true ) ||
|
|
( mtcTimer.active == false ) ||
|
|
( mtcTimer.tid == NULL ))
|
|
{
|
|
return (true);
|
|
}
|
|
return (false);
|
|
}
|
|
|
|
|
|
bool mtcTimer_expired ( struct mtc_timer * mtcTimer_ptr )
|
|
{
|
|
if ( mtcTimer_ptr )
|
|
{
|
|
if (( mtcTimer_ptr->ring == true ) ||
|
|
( mtcTimer_ptr->active == false ) ||
|
|
( mtcTimer_ptr->tid == NULL ))
|
|
{
|
|
return (true);
|
|
}
|
|
}
|
|
return (false);
|
|
}
|
|
|
|
|
|
void mtcTimer_reset ( struct mtc_timer & mtcTimer )
|
|
{
|
|
if ( mtcTimer.tid )
|
|
_timer_stop ( &mtcTimer , false );
|
|
|
|
if ( mtcTimer.active )
|
|
mtcTimer.active = false ;
|
|
|
|
mtcTimer.ring = false ;
|
|
}
|
|
|
|
void mtcTimer_reset ( struct mtc_timer * mtcTimer_ptr )
|
|
{
|
|
if ( mtcTimer_ptr )
|
|
{
|
|
if ( mtcTimer_ptr->tid )
|
|
_timer_stop ( mtcTimer_ptr , false );
|
|
|
|
if ( mtcTimer_ptr->active )
|
|
mtcTimer_ptr->active = false ;
|
|
|
|
mtcTimer_ptr->ring = false ;
|
|
}
|
|
}
|
|
|
|
/*************************************************************************
|
|
*
|
|
* Issue: These static vars record unknown/stale timer data.
|
|
* The time of the ring, the TID, and the number of outstanding
|
|
* timers at that time. They are defaulted to zero and should
|
|
* remain that way. The mtcTimer_dump_data utility can be
|
|
* called periodically by a process audit, will create a Swerr
|
|
* log with the recorded data and then clear the these vars only
|
|
* to allow the next occurance to be recorded and loged on the
|
|
* next audit interval.
|
|
*
|
|
**************************************************************************/
|
|
static timer_t * stale_tid_ptr = NULL ;
|
|
static string stale_tid_time = "" ;
|
|
static int stale_tid_count = 0 ;
|
|
|
|
/* Dump the mtcTimer data - currently only dumps stale data */
|
|
void mtcTimer_dump_data ( void )
|
|
{
|
|
if ( stale_tid_ptr )
|
|
{
|
|
slog ("Unknown timer fired at '%s' with tid '%p' ; module has %d loaded timers\n",
|
|
stale_tid_time.c_str(),
|
|
stale_tid_ptr,
|
|
stale_tid_count );
|
|
|
|
stale_tid_ptr = NULL ;
|
|
stale_tid_time.clear() ;
|
|
stale_tid_count = 0 ;
|
|
}
|
|
}
|
|
|
|
int _timer_stop_tid ( timer_t * tid_ptr , bool int_safe )
|
|
{
|
|
int rc = PASS ;
|
|
|
|
#ifdef UNUSED
|
|
UNUSED (int_safe);
|
|
#endif
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Issue reported a segfault that was a result of trying to cancel
|
|
* a timer based on a stale/unknown TID. Its better to record the error
|
|
* and leave the timer alone than to try and cancel and get a segfault.
|
|
*
|
|
* This update records the fact that this condition has happened only
|
|
* to be logged by the host process with a call to mtcTimer_dump_data
|
|
* and debugged after-the-fact.
|
|
*
|
|
**********************************************************************/
|
|
if ( stale_tid_ptr == NULL )
|
|
{
|
|
stale_tid_ptr = tid_ptr ;
|
|
stale_tid_time = pt();
|
|
stale_tid_count = timer_count ;
|
|
}
|
|
|
|
/* This defined out due to potential for segfault */
|
|
#ifdef WANT_TIMER_STOP_BY_ID
|
|
|
|
if ( tid_ptr )
|
|
{
|
|
struct mtc_timer ghostTimer ;
|
|
ghostTimer.value.it_value.tv_sec = 0;
|
|
ghostTimer.value.it_value.tv_nsec = 0;
|
|
ghostTimer.value.it_interval.tv_sec = 0;
|
|
ghostTimer.value.it_interval.tv_nsec = 0;
|
|
if ( timer_settime (*tid_ptr, 0, &ghostTimer.value, NULL) == -1 )
|
|
{
|
|
if ( int_safe == false )
|
|
{
|
|
elog ("ghostTimer stop (timer_settime) failed\n");
|
|
}
|
|
rc = FAIL_TIMER_STOP ;
|
|
goto _timer_stop_tid_out ;
|
|
}
|
|
|
|
timer_delete (*tid_ptr);
|
|
if ( timer_count )
|
|
timer_count-- ;
|
|
}
|
|
else if ( int_safe == false )
|
|
{
|
|
elog ("called with NULL TID (%d)\n", timer_count);
|
|
}
|
|
|
|
if ( int_safe == false )
|
|
{
|
|
tlog ("Remaining outstanding timers: %d\n", timer_count );
|
|
}
|
|
|
|
_timer_stop_tid_out:
|
|
|
|
#endif
|
|
|
|
return rc ;
|
|
}
|
|
|
|
int mtcTimer_stop_tid ( timer_t * tid_ptr )
|
|
{
|
|
return (_timer_stop_tid ( tid_ptr , false ));
|
|
}
|
|
|
|
int mtcTimer_stop_tid_int_safe ( timer_t * tid_ptr )
|
|
{
|
|
return (_timer_stop_tid ( tid_ptr , true ));
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
void _timer_init ( struct mtc_timer * mtcTimer_ptr , string hostname, string service )
|
|
{
|
|
if ( mtcTimer_ptr == NULL)
|
|
{
|
|
return ;
|
|
}
|
|
|
|
if ( hostname.empty() )
|
|
mtcTimer_ptr->hostname = "unset_hostname" ;
|
|
else
|
|
mtcTimer_ptr->hostname = hostname ;
|
|
|
|
if ( service.empty() )
|
|
mtcTimer_ptr->service = "unset_service" ;
|
|
else
|
|
mtcTimer_ptr->service = service ;
|
|
|
|
if (( mtcTimer_ptr->init == TIMER_INIT_SIGNATURE ) && ( mtcTimer_ptr->tid != NULL ))
|
|
{
|
|
slog ("%s '%s' service is unexpectedly re-initializated ; stopping active timer\n",
|
|
hostname.c_str(),
|
|
mtcTimer_ptr->service.c_str());
|
|
mtcTimer_reset ( mtcTimer_ptr );
|
|
}
|
|
|
|
tlog ("%s '%s' service initialized (%p)\n",
|
|
hostname.c_str(),
|
|
mtcTimer_ptr->service.c_str(),
|
|
mtcTimer_ptr->tid) ;
|
|
|
|
mtcTimer_ptr->init = TIMER_INIT_SIGNATURE ;
|
|
mtcTimer_ptr->tid = NULL ;
|
|
mtcTimer_ptr->secs = 0 ;
|
|
mtcTimer_ptr->msec = 0 ;
|
|
mtcTimer_ptr->ring = false ;
|
|
mtcTimer_ptr->active= false ;
|
|
mtcTimer_ptr->error = false ;
|
|
mtcTimer_ptr->mutex = false ;
|
|
|
|
}
|
|
|
|
/* Init / clean a user timer */
|
|
void _timer_fini ( struct mtc_timer * mtcTimer_ptr )
|
|
{
|
|
mtcTimer_reset ( mtcTimer_ptr );
|
|
mtcTimer_ptr->init = 0 ;
|
|
}
|
|
|
|
/* de-init a user timer */
|
|
void mtcTimer_fini ( struct mtc_timer & mtcTimer )
|
|
{
|
|
_timer_fini (&mtcTimer );
|
|
}
|
|
|
|
/* de-init a user timer */
|
|
void mtcTimer_fini ( struct mtc_timer* mtcTimer_ptr )
|
|
{
|
|
_timer_fini ( mtcTimer_ptr );
|
|
}
|
|
|
|
|
|
/* Init / clean a user timer */
|
|
void mtcTimer_init ( struct mtc_timer * mtcTimer_ptr )
|
|
{
|
|
_timer_init ( mtcTimer_ptr, "" , "" );
|
|
}
|
|
|
|
/* Init / clean a user timer */
|
|
void mtcTimer_init ( struct mtc_timer * mtcTimer_ptr , string hostname, string service)
|
|
{
|
|
_timer_init ( mtcTimer_ptr, hostname , service );
|
|
}
|
|
|
|
/* Init / clean a user timer */
|
|
void mtcTimer_init ( struct mtc_timer & mtcTimer )
|
|
{
|
|
_timer_init (&mtcTimer, "", "" );
|
|
}
|
|
|
|
/* Init / clean a user timer */
|
|
void mtcTimer_init ( struct mtc_timer & mtcTimer , string hostname )
|
|
{
|
|
_timer_init (&mtcTimer, hostname, "" );
|
|
}
|
|
|
|
/* Init / clean a user timer */
|
|
void mtcTimer_init ( struct mtc_timer & mtcTimer , string hostname, string service )
|
|
{
|
|
_timer_init (&mtcTimer, hostname, service );
|
|
}
|
|
|
|
/* Wait Utilities - only use during init */
|
|
|
|
static struct mtc_timer waitTimer ;
|
|
|
|
static void waitTimer_handler ( int sig, siginfo_t *si, void *uc)
|
|
{
|
|
timer_t * tid_ptr = (void**)si->si_value.sival_ptr ;
|
|
|
|
/* Avoid compiler errors/warnings for parms we must
|
|
* have but currently do nothing with */
|
|
UNUSED(sig);
|
|
UNUSED(uc);
|
|
if ( !(*tid_ptr) )
|
|
{
|
|
return ;
|
|
}
|
|
/* is base mtc timer */
|
|
else if (( *tid_ptr == waitTimer.tid ) )
|
|
{
|
|
waitTimer.ring = true ;
|
|
mtcTimer_stop ( waitTimer );
|
|
}
|
|
else
|
|
{
|
|
wlog ("Unexpected timer (%p)\n", *tid_ptr );
|
|
mtcTimer_stop_tid ( tid_ptr );
|
|
}
|
|
}
|
|
|
|
void mtcWait_msecs ( int millisecs )
|
|
{
|
|
if ( waitTimer.init != TIMER_INIT_SIGNATURE )
|
|
mtcTimer_init ( waitTimer , "localhost", "mtcWait_msecs" );
|
|
|
|
if ( millisecs > 999 )
|
|
{
|
|
wlog ("Wait request too long, rounding down to 999\n");
|
|
millisecs = 999 ;
|
|
}
|
|
mtcTimer_start_msec ( waitTimer, waitTimer_handler, millisecs );
|
|
do
|
|
{
|
|
usleep (1000);
|
|
daemon_signal_hdlr ();
|
|
} while ( waitTimer.ring == false ) ;
|
|
}
|
|
|
|
void mtcWait_secs ( int secs )
|
|
{
|
|
if ( waitTimer.init != TIMER_INIT_SIGNATURE )
|
|
mtcTimer_init ( waitTimer , "localhost", "mtcWait_secs" );
|
|
|
|
mtcTimer_start ( waitTimer, waitTimer_handler, secs );
|
|
do
|
|
{
|
|
sleep (1);
|
|
daemon_signal_hdlr ();
|
|
} while ( waitTimer.ring == false ) ;
|
|
}
|
|
|
|
void mtcTimer_mem_log ( void )
|
|
{
|
|
char str [64] ;
|
|
sprintf ( str, "Working Timers: %d\n", timer_count );
|
|
mem_log ( str );
|
|
}
|