Files
m241Neelima/components/ip_net2-6.9/ipcom/src/ipcom_tmo.c
T
2026-07-30 11:19:44 +05:30

568 lines
17 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipcom_tmo.c,v $ $Revision: 1.23.126.8 $
* $Source: /home/interpeak/CVSRoot/ipcom/src/ipcom_tmo.c,v $
* $Author: csun $ $Date: 2017-08-23 02:00:04 $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Lennart Bang <lob@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
* Interpeak timeout server.
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipcom_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include "ipcom_tmo.h"
#include "ipcom_err.h"
#include "ipcom_list.h"
#include "ipcom_clib.h"
#include "ipcom_os.h"
#include "ipcom_syslog.h"
/*
****************************************************************************
* 4 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 5 DEFINES
****************************************************************************
*/
#define IPCOM_SYSLOG_PRIORITY IPCOM_SYSLOG_IPCOM_PRIORITY
#define IPCOM_SYSLOG_FACILITY IPCOM_LOG_IPCOM
/* Protect timeout server API functions from race conditions. */
#define IPCOM_USE_TMOMUTEX
#ifndef IPCOM_USE_TMOMUTEX
#define ipcom_mutex_create(x) IP_NOOP
#define ipcom_mutex_delete(x) IP_NOOP
#define ipcom_mutex_lock(x) IP_NOOP
#define ipcom_mutex_unlock(x) IP_NOOP
#endif
#ifdef IP_DEBUG
#define IPCOM_TMO_POST
#endif
/*
****************************************************************************
* 6 TYPES
****************************************************************************
*/
/*
*===========================================================================
* Global ipcom_tmo data
*===========================================================================
* Internal global Ipcom_tmo data.
*/
typedef struct Ipcom_tmo_data_struct
{
#ifdef IPCOM_USE_TMOMUTEX
Ipcom_mutex mutex;
#endif
/*
* The tick daemon will sleep on this semaphore with a timeout
* until the text timer expires
*/
Ipcom_block sem;
/* Collection of active timers */
Ipcom_pqueue *head;
}
Ipcom_tmo_data;
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
IP_STATIC Ip_err ipcom_tmo_init(void *ununsed);
IP_STATIC IPCOM_PROCESS(ipcom_tickd);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
*===========================================================================
* Global ipcom_tmo data
*===========================================================================
*/
IP_STATIC Ipcom_tmo_data ipcom_tmo;
IP_STATIC Ipcom_once_t ipcom_tmo_once = IPCOM_ONCE_INIT;
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
#ifdef IPCOM_TMO_POST
enum Ipcom_tmo_post_state {
/* Timer is pending */
IPCOM_TMO_PENDING,
/* Timer has been run */
IPCOM_TMO_RUN,
/* Timer is pending and will be reset when run */
IPCOM_TMO_PENDING_RESET,
/* Timer as been run and reset to pending again */
IPCOM_TMO_RUN_RESET
};
struct Ipcom_tmo_post {
Ipcom_tmo tmo;
/* State of this POST timer */
enum Ipcom_tmo_post_state state;
/* Protects 'state' */
Ipcom_mutex mutex;
/* Will be posted each time the timeout handler is run */
Ipcom_block sem;
};
IP_STATIC void
ipcom_tmo_post_assert(Ip_bool pred)
{
if (!pred)
{
ipcom_debug_printf("IPCOM tmo POST failed!");
IP_PANIC();
}
}
IP_STATIC Ip_s32
ipcom_tmo_post_cb(Ipcom_tmo *tmo_arg, void *cookie)
{
Ip_s32 restart = 0;
IPCOM_UNUSED_ARG(tmo_arg);
if (cookie)
{
struct Ipcom_tmo_post *tmo = cookie;
switch (tmo->state)
{
case IPCOM_TMO_PENDING:
case IPCOM_TMO_RUN_RESET:
tmo->state = IPCOM_TMO_RUN;
break;
case IPCOM_TMO_PENDING_RESET:
tmo->state = IPCOM_TMO_RUN_RESET;
restart = 1;
break;
default:
ipcom_tmo_post_assert(IP_FALSE);
break;
}
ipcom_block_post(tmo->sem);
}
return restart;
}
IP_STATIC void
ipcom_tmo_post_init(struct Ipcom_tmo_post *tmo)
{
IPCOM_TMO_INIT(&tmo->tmo);
ipcom_tmo_post_assert(IPCOM_TMO_PENDING(&tmo->tmo) == IP_FALSE);
ipcom_tmo_post_assert(ipcom_block_create(&tmo->sem)
== IPCOM_SUCCESS);
}
IP_STATIC void
ipcom_tmo_post_finish(struct Ipcom_tmo_post *tmo)
{
ipcom_tmo_post_assert(IPCOM_TMO_PENDING(&tmo->tmo) == IP_FALSE);
ipcom_tmo_post_assert(ipcom_block_delete(&tmo->sem)
== IPCOM_SUCCESS);
}
IP_STATIC void
ipcom_tmo_wait(struct Ipcom_tmo_post *tmo)
{
ipcom_tmo_post_assert(ipcom_block_wait(tmo->sem,
(Ip_s32)ipcom_tmo_get(&tmo->tmo) * 100)
== IPCOM_SUCCESS);
}
/*
*===========================================================================
* ipcom_tmo_post
*===========================================================================
* Description: Runs self-test on the timeout handler.
* Parameters:
* Returns:
*
*/
IP_STATIC
IPCOM_PROCESS(ipcom_tmo_post)
{
struct Ipcom_tmo_post tmo1;
struct Ipcom_tmo_post tmo2;
const Ip_u32 msec = 200;
ipcom_proc_init();
ipcom_tmo_post_init(&tmo1);
ipcom_tmo_post_init(&tmo2);
/*
* Verify that a timer handler is run
*/
tmo1.state = IPCOM_TMO_PENDING;
ipcom_tmo_post_assert(ipcom_tmo_request(&tmo1.tmo,
ipcom_tmo_post_cb,
&tmo1,
msec) == IPCOM_SUCCESS);
ipcom_tmo_post_assert(IPCOM_TMO_PENDING(&tmo1.tmo));
ipcom_tmo_wait(&tmo1);
ipcom_tmo_post_assert(tmo1.state == IPCOM_TMO_RUN);
/*
* Verify that it is possible to cancel a timer and that the timer
* handler is not run in that case.
*/
tmo1.state = tmo2.state = IPCOM_TMO_PENDING;
ipcom_tmo_post_assert(ipcom_tmo_request(&tmo1.tmo,
ipcom_tmo_post_cb,
&tmo1,
msec) == IPCOM_SUCCESS);
ipcom_tmo_post_assert(ipcom_tmo_request(&tmo2.tmo,
ipcom_tmo_post_cb,
&tmo2,
msec) == IPCOM_SUCCESS);
ipcom_tmo_post_assert(IPCOM_TMO_PENDING(&tmo1.tmo));
ipcom_tmo_post_assert(IPCOM_TMO_PENDING(&tmo2.tmo));
ipcom_tmo_post_assert(ipcom_tmo_cancel(&tmo1.tmo) == IPCOM_SUCCESS);
ipcom_tmo_post_assert(!IPCOM_TMO_PENDING(&tmo1.tmo));
ipcom_tmo_post_assert(IPCOM_TMO_PENDING(&tmo2.tmo));
ipcom_tmo_post_assert(ipcom_tmo_cancel(&tmo1.tmo) == IPCOM_SUCCESS);
ipcom_tmo_wait(&tmo2);
ipcom_tmo_post_assert(tmo1.state == IPCOM_TMO_PENDING);
ipcom_tmo_post_assert(tmo2.state == IPCOM_TMO_RUN);
/*
* Verify that the timer will reschedule itself if the handler
* returns 1.
*/
tmo1.state = IPCOM_TMO_PENDING_RESET;
ipcom_tmo_post_assert(ipcom_tmo_request(&tmo1.tmo,
ipcom_tmo_post_cb,
&tmo1,
msec) == IPCOM_SUCCESS);
ipcom_tmo_wait(&tmo1);
ipcom_tmo_post_assert(tmo1.state == IPCOM_TMO_RUN_RESET);
/*
* Note, on an SMP system, the timer might not have been put
* back onto the queue yet by ipcom_tickd(). So, wait a short while
* (msec/4) using the second timer to give a chance for the first
* timer to be requeued, before checking that tmo1 is pending.
*/
tmo2.state = IPCOM_TMO_PENDING;
ipcom_tmo_post_assert(ipcom_tmo_request(&tmo2.tmo,
ipcom_tmo_post_cb,
&tmo2,
msec/4) == IPCOM_SUCCESS);
ipcom_tmo_wait(&tmo2);
ipcom_tmo_post_assert(IPCOM_TMO_PENDING(&tmo1.tmo));
ipcom_tmo_wait(&tmo1);
ipcom_tmo_post_assert(tmo1.state == IPCOM_TMO_RUN);
ipcom_tmo_post_assert(!IPCOM_TMO_PENDING(&tmo1.tmo));
ipcom_tmo_post_finish(&tmo1);
ipcom_tmo_post_finish(&tmo2);
IPCOM_LOG0(INFO, "ipcom_tmo :: POST successful");
ipcom_proc_exit();
}
#endif
/*
*===========================================================================
* ipcom_tickd
*===========================================================================
* Description:
*
*/
IP_STATIC
IPCOM_PROCESS(ipcom_tickd)
{
ipcom_proc_init();
IPCOM_LOG0(DEBUG, "ipcom_tickd :: starting tickd");
/*********** tick loop ***********/
for (;;)
{
Ipcom_tmo2 *tmo;
Ip_s32 msec;
ipcom_mutex_lock(ipcom_tmo.mutex);
while (IP_NULL != (tmo = ipcom_pqueue_get_next(ipcom_tmo.head))
&& 0 == (msec = (Ip_s32)ipcom_tmo2_get(tmo)))
{
int cb_ret;
tmo = ipcom_pqueue_remove_next(ipcom_tmo.head);
ipcom_mutex_unlock(ipcom_tmo.mutex);
ip_assert(tmo != IP_NULL);
cb_ret = ((Ipcom_tmo_func)tmo->func)((Ipcom_tmo*)tmo, tmo->cookie);
ipcom_mutex_lock(ipcom_tmo.mutex);
if (cb_ret)
(void)ipcom_tmo2_request_timeval(tmo->head,
tmo,
tmo->func,
tmo->cookie,
&tmo->duration);
}
if (tmo == IP_NULL)
msec = IPC_TIMEOUT_INFINITE;
ipcom_mutex_unlock(ipcom_tmo.mutex);
(void)ipcom_block_wait(ipcom_tmo.sem, msec);
}
/*NOT REACHED: ipcom_proc_exit();*/
}
/*
*===========================================================================
* ipcom_tmo_init
*===========================================================================
* Description: Initialize and create timeout server.
* Parameters: .
* Returns: .
*
*/
IP_STATIC Ip_err
ipcom_tmo_init(void *unused)
{
Ip_err err;
Ipcom_proc_attr attr;
IPCOM_UNUSED_ARG(unused);
err = ipcom_block_create(&ipcom_tmo.sem);
ip_assert(err == IPCOM_SUCCESS);
if (err != IPCOM_SUCCESS)
IP_PANIC();
err = ipcom_mutex_create(&ipcom_tmo.mutex);
ip_assert(err == IPCOM_SUCCESS);
if (err != IPCOM_SUCCESS)
IP_PANIC();
ipcom_tmo.head = ipcom_tmo2_new();
ip_assert(ipcom_tmo.head != IP_NULL);
if (ipcom_tmo.head == IP_NULL)
IP_PANIC();
ipcom_proc_attr_init(&attr);
attr.priority = IPCOM_PRIORITY_MAX;
err = ipcom_proc_acreate("ipcom_tickd", ipcom_tickd, &attr, IP_NULL);
ip_assert(err == IPCOM_SUCCESS);
#ifdef IPCOM_TMO_POST
--attr.priority;
err = ipcom_proc_acreate("ipcom_tmo_post", ipcom_tmo_post, &attr, IP_NULL);
ip_assert(err == IPCOM_SUCCESS);
#endif
return err;
}
/*
****************************************************************************
* 10 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipcom_tmo_request
*===========================================================================
* Description: Request a timeout in 'msec' milliseconds. If the timeout
* triggers the function 'func' is called with the timeout
* 'tmo'.
* Parameters: tmo A pointer to a Ipcom_tmo structure which stores
* information about the timeout and serves as a handle
* to cancel the timeout.
* func A user callback function that is called if/when the
* timeout triggers.
* cookie A user 32-bit value that is passed with the timeout
* callback function 'func'.
* msec Number of timeout milliseconds.
* Returns: IPCOM_SUCCESS - Success.
*
*/
IP_PUBLIC Ip_err
ipcom_tmo_request(Ipcom_tmo *tmo, Ipcom_tmo_func func, void *cookie, Ip_u32 msec)
{
Ip_err err;
err = ipcom_once(&ipcom_tmo_once, ipcom_tmo_init, IP_NULL);
if (err != IPCOM_SUCCESS)
return err;
ipcom_mutex_lock(ipcom_tmo.mutex);
err = ipcom_tmo2_request(ipcom_tmo.head,
&tmo->tmo,
(Ipcom_tmo2_func) func,
cookie,
msec);
ipcom_mutex_unlock(ipcom_tmo.mutex);
/*
* Make sure that 'ipcom_tickd' recalculates the time to the
* expiration of the next timer.
*/
ipcom_block_post(ipcom_tmo.sem);
return err;
}
/*
*===========================================================================
* ipcom_tmo_cancel
*===========================================================================
* Description: Cancel a pending timeout. There is no danger in calling this
* function on a timeout that is not pending.
* Parameters: tmo - The same Ipcom_tmo timeout handle that was given
* upon requesting the timeout.
* Returns: IPCOM_SUCCESS - Success.
*
*/
IP_PUBLIC Ip_err
ipcom_tmo_cancel(Ipcom_tmo *tmo)
{
Ip_err err;
err = ipcom_once(&ipcom_tmo_once, ipcom_tmo_init, IP_NULL);
if (err != IPCOM_SUCCESS)
return err;
ipcom_mutex_lock(ipcom_tmo.mutex);
err = ipcom_tmo2_cancel(&tmo->tmo);
ipcom_mutex_unlock(ipcom_tmo.mutex);
return (err == IPCOM_ERR_NOT_STARTED ? IPCOM_SUCCESS : err);
}
/*
*===========================================================================
* ipcom_tmo_reset
*===========================================================================
* Description: Reset a timeout. The timeout is started over with its
* original time.
* Parameters: tmo - The same Ipcom_tmo timeout handle that was given
* upon requesting the timeout.
* Returns: IPCOM_SUCCESS - Success.
*
*/
IP_PUBLIC Ip_err
ipcom_tmo_reset(Ipcom_tmo *tmo)
{
Ip_err err;
err = ipcom_once(&ipcom_tmo_once, ipcom_tmo_init, IP_NULL);
if (err != IPCOM_SUCCESS)
return err;
ipcom_mutex_lock(ipcom_tmo.mutex);
err = ipcom_tmo2_reset(&tmo->tmo);
ipcom_mutex_unlock(ipcom_tmo.mutex);
return err;
}
/*
*===========================================================================
* ipcom_tmo_get
*===========================================================================
* Description: Get milliseconds left to timeout.
* Parameters: tmo - The same Ipcom_tmo timeout handle that was given
* upon requesting the timeout.
* Returns: Number of milliseconds before timeout.
*
*/
IP_PUBLIC Ip_u32
ipcom_tmo_get(Ipcom_tmo *tmo)
{
Ip_u32 msec;
if (ipcom_once(&ipcom_tmo_once, ipcom_tmo_init, IP_NULL) != IPCOM_SUCCESS)
return 0;
ipcom_mutex_lock(ipcom_tmo.mutex);
msec = ipcom_tmo2_get(&tmo->tmo);
ipcom_mutex_unlock(ipcom_tmo.mutex);
return msec;
}
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/