395 lines
11 KiB
C
395 lines
11 KiB
C
/*
|
|
******************************************************************************
|
|
* SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipcom_tmo2.c,v $ $Revision: 1.7.18.4 $
|
|
* $Source: /home/interpeak/CVSRoot/ipcom/src/ipcom_tmo2.c,v $
|
|
* $Author: hxie $ $Date: 2013-08-02 07:48:53 $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
* Interpeak timeout module. The difference between this module and the one
|
|
* in ipcom_tmo.h is that this module does not use an external timeout daemon.
|
|
* It is driven by the process itself, the restriction is that it can only
|
|
* be used by application that is driven solely by socket events.
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#include "ipcom_config.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include "ipcom_clib.h"
|
|
#include "ipcom_err.h"
|
|
#include "ipcom_list.h"
|
|
#include "ipcom_os.h"
|
|
#include "ipcom_syslog.h"
|
|
#include "ipcom_time.h"
|
|
#include "ipcom_tmo2.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_tmo2_pqueue_cmp_func
|
|
*===========================================================================
|
|
* Description: Compares two timeouts entries.
|
|
* Parameters: tmo1 -
|
|
* tmo2 -
|
|
* Returns: 1 if tmo1 timeouts before tmo2
|
|
* 0 if tmo1 and tmo2 times out at the same time
|
|
* -1 if tmo1 timeouts after tmo2
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipcom_tmo2_pqueue_cmp_func(IP_CONST Ipcom_tmo2 *tmo1,
|
|
IP_CONST Ipcom_tmo2 *tmo2)
|
|
{
|
|
if (ip_timeval_cmp(&tmo1->abs, &tmo2->abs, <))
|
|
return 1;
|
|
if (ip_timeval_cmp(&tmo1->abs, &tmo2->abs, >))
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_tmo2_pqueue_store_index
|
|
*===========================================================================
|
|
* Description: Stores the index the passed object has in the priority queue.
|
|
* Parameters: tmo - the timeout object that has been stored in the queue.
|
|
* indx - the index the timeout object has in the queue.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipcom_tmo2_pqueue_store_index(Ipcom_tmo2 *tmo, int indx)
|
|
{
|
|
tmo->pqindex = indx;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_tmo2_new
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ipcom_pqueue *
|
|
ipcom_tmo2_new(void)
|
|
{
|
|
return ipcom_pqueue_new((Ipcom_pqueue_cmp_func) ipcom_tmo2_pqueue_cmp_func,
|
|
(Ipcom_pqueue_store_index) ipcom_tmo2_pqueue_store_index);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_tmo2_delete
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC void
|
|
ipcom_tmo2_delete(Ipcom_pqueue *head)
|
|
{
|
|
ipcom_pqueue_delete(head);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_tmo2_request
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipcom_tmo2_request(Ipcom_pqueue *head,
|
|
Ipcom_tmo2 *tmo,
|
|
Ipcom_tmo2_func func,
|
|
void *cookie,
|
|
Ip_u32 msec)
|
|
{
|
|
struct Ip_timeval duration;
|
|
|
|
duration.tv_sec = msec / 1000;
|
|
duration.tv_usec = (msec % 1000) * 1000;
|
|
return ipcom_tmo2_request_timeval(head, tmo, func, cookie, &duration);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_tmo2_request
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipcom_tmo2_request_timeval(Ipcom_pqueue *head,
|
|
Ipcom_tmo2 *tmo,
|
|
Ipcom_tmo2_func func,
|
|
void *cookie,
|
|
IP_CONST struct Ip_timeval *duration)
|
|
{
|
|
if (IPCOM_TMO2_PENDING(tmo))
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_ALREADY_STARTED;
|
|
}
|
|
|
|
tmo->head = head;
|
|
tmo->func = func;
|
|
tmo->cookie = cookie;
|
|
tmo->duration = *duration;
|
|
|
|
ipcom_microtime(&tmo->abs);
|
|
ip_timeval_add(&tmo->abs, duration, &tmo->abs);
|
|
|
|
return ipcom_pqueue_insert(head, tmo);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_tmo2_cancel
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipcom_tmo2_cancel(Ipcom_tmo2 *tmo)
|
|
{
|
|
if (IPCOM_TMO2_PENDING(tmo) == IP_FALSE)
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_NOT_STARTED;
|
|
}
|
|
|
|
(void)ipcom_pqueue_remove(tmo->head, tmo->pqindex);
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_tmo2_reset
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipcom_tmo2_reset(Ipcom_tmo2 *tmo)
|
|
{
|
|
if (IPCOM_TMO2_PENDING(tmo) == IP_FALSE)
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_NOT_STARTED;
|
|
}
|
|
(void)ipcom_pqueue_remove(tmo->head, tmo->pqindex);
|
|
return ipcom_tmo2_request_timeval(tmo->head,
|
|
tmo, tmo->func,
|
|
tmo->cookie,
|
|
&tmo->duration);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_tmo2_get
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_u32
|
|
ipcom_tmo2_get(Ipcom_tmo2 *tmo)
|
|
{
|
|
struct Ip_timeval tv;
|
|
|
|
if (IPCOM_TMO2_PENDING(tmo) == IP_FALSE)
|
|
return 0;
|
|
|
|
ipcom_microtime(&tv);
|
|
if (ip_timeval_cmp(&tmo->abs, &tv, <))
|
|
/* Past expiration time */
|
|
return 0;
|
|
ip_timeval_sub(&tmo->abs, &tv, &tv);
|
|
return (Ip_u32) (tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_tmo2_select
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipcom_tmo2_select(Ipcom_pqueue *head,
|
|
int nfds,
|
|
Ip_fd_set *readfds,
|
|
Ip_fd_set *writefds,
|
|
Ip_fd_set *exceptfds,
|
|
struct Ip_timeval *timeout)
|
|
{
|
|
struct Ip_timeval tv;
|
|
struct Ip_timeval *ptv;
|
|
Ipcom_tmo2 *tmo;
|
|
Ip_fd_set rset;
|
|
Ip_fd_set wset;
|
|
Ip_fd_set eset;
|
|
Ip_bool user_tmo;
|
|
int ret;
|
|
|
|
ipcom_memset(&rset, 0, sizeof(rset));
|
|
ipcom_memset(&wset, 0, sizeof(wset));
|
|
ipcom_memset(&eset, 0, sizeof(eset));
|
|
/* Save the callers select set(s) */
|
|
if (readfds)
|
|
rset = *readfds;
|
|
if (writefds)
|
|
wset = *writefds;
|
|
if (exceptfds)
|
|
eset = *exceptfds;
|
|
|
|
for (;;)
|
|
{
|
|
ipcom_microtime(&tv);
|
|
while (IP_NULL != (tmo = ipcom_pqueue_get_next(head))
|
|
&& !ip_timeval_cmp(&tmo->abs, &tv, >))
|
|
{
|
|
tmo = ipcom_pqueue_remove_next(head);
|
|
ip_assert(tmo != IP_NULL);
|
|
ret = tmo->func(tmo->cookie);
|
|
if (ret)
|
|
(void)ipcom_tmo2_request_timeval(tmo->head,
|
|
tmo,
|
|
tmo->func,
|
|
tmo->cookie,
|
|
&tmo->duration);
|
|
}
|
|
|
|
ptv = timeout;
|
|
user_tmo = IP_TRUE;
|
|
if (tmo)
|
|
{
|
|
ip_timeval_sub(&tmo->abs, &tv, &tv);
|
|
if (timeout == IP_NULL || ip_timeval_cmp(&tv, timeout, <))
|
|
{
|
|
ptv = &tv;
|
|
user_tmo = IP_FALSE;
|
|
if (timeout != IP_NULL)
|
|
ip_timeval_sub(timeout, &tv, timeout);
|
|
}
|
|
}
|
|
|
|
ret = ipcom_socketselect(nfds, readfds, writefds, exceptfds, ptv);
|
|
if (ret > 0
|
|
|| (ret < 0 && ipcom_errno != IP_ERRNO_EINTR)
|
|
|| (ret == 0 && user_tmo))
|
|
/* Sockets ready || got error (but interrupts are ignored) || user timeout */
|
|
break;
|
|
|
|
/* Restore the callers original select set(s) */
|
|
if (readfds)
|
|
*readfds = rset; /*lint !e644 */
|
|
if (writefds)
|
|
*writefds = wset; /*lint !e644 */
|
|
if (exceptfds)
|
|
*exceptfds = eset; /*lint !e644 */
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|
|
|
|
|