/* ****************************************************************************** * 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 ****************************************************************************** */ /* **************************************************************************** * 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 **************************************************************************** */