metal/mtce-common/src/common/nodeTimers.cpp

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 );
}