original files of m241
This commit is contained in:
@@ -0,0 +1,567 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
* 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
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user