40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi/*
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * CDDL HEADER START
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi *
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * The contents of this file are subject to the terms of the
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Common Development and Distribution License (the "License").
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * You may not use this file except in compliance with the License.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi *
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * or http://www.opensolaris.org/os/licensing.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * See the License for the specific language governing permissions
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * and limitations under the License.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi *
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * When distributing Covered Code, include this CDDL HEADER in each
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * If applicable, add the following below this CDDL HEADER, with the
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * fields enclosed by brackets "[]" replaced with your own identifying
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * information: Portions Copyright [yyyy] [name of copyright owner]
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi *
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * CDDL HEADER END
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi/*
2c2c41837e330b002c4220a39638150db504fe0evi * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Use is subject to license terms.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#pragma ident "%Z%%M% %I% %E% SMI"
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi/*
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Simple implementation of timeout functionality. The granuality is a sec
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#include <pthread.h>
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#include <stdlib.h>
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331viuint_t sip_timeout(void *arg, void (*callback_func)(void *),
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi struct timeval *timeout_time);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331viboolean_t sip_untimeout(uint_t);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vitypedef struct timeout {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi struct timeout *sip_timeout_next;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi hrtime_t sip_timeout_val;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi void (*sip_timeout_callback_func)(void *);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi void *sip_timeout_callback_func_arg;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi int sip_timeout_id;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi} sip_timeout_t;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vistatic pthread_mutex_t timeout_mutex = PTHREAD_MUTEX_INITIALIZER;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vistatic pthread_cond_t timeout_cond_var = PTHREAD_COND_INITIALIZER;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vistatic sip_timeout_t *timeout_list;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vistatic sip_timeout_t *timeout_current_start;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vistatic sip_timeout_t *timeout_current_end;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi/*
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * LONG_SLEEP_TIME = (24 * 60 * 60 * NANOSEC)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#define LONG_SLEEP_TIME (0x15180LL * 0x3B9ACA00LL)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331viuint_t timer_id = 0;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi/*
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Invoke the callback function
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi/* ARGSUSED */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vistatic void *
40cb5e5daa7b80bb70fcf8dadfb20f9281566331visip_run_to_functions(void *arg)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi{
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_timeout_t *timeout = NULL;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) pthread_mutex_lock(&timeout_mutex);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi while (timeout_current_start != NULL) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timeout = timeout_current_start;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (timeout_current_end == timeout_current_start)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timeout_current_start = timeout_current_end = NULL;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi else
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timeout_current_start = timeout->sip_timeout_next;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) pthread_mutex_unlock(&timeout_mutex);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timeout->sip_timeout_callback_func(
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timeout->sip_timeout_callback_func_arg);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi free(timeout);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) pthread_mutex_lock(&timeout_mutex);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) pthread_mutex_unlock(&timeout_mutex);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi pthread_exit(NULL);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi return ((void *)0);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi}
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi/*
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * In the very very unlikely case timer id wraps around and we have two timers
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * with the same id. If that happens timer with the least amount of time left
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * will be deleted. In case both timers have same time left than the one that
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * was scheduled first will be deleted as it will be in the front of the list.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331viboolean_t
40cb5e5daa7b80bb70fcf8dadfb20f9281566331visip_untimeout(uint_t id)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi{
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi boolean_t ret = B_FALSE;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_timeout_t *current, *last;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi last = NULL;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) pthread_mutex_lock(&timeout_mutex);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi /*
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Check if this is in the to-be run list
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (timeout_current_start != NULL) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi current = timeout_current_start;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi while (current != NULL) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (current->sip_timeout_id == id) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (current == timeout_current_start) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timeout_current_start =
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi current->sip_timeout_next;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi } else {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi last->sip_timeout_next =
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi current->sip_timeout_next;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (current == timeout_current_end)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timeout_current_end = last;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (current->sip_timeout_callback_func_arg !=
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi NULL) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi free(current->
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_timeout_callback_func_arg);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi current->sip_timeout_callback_func_arg =
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi NULL;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi free(current);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi ret = B_TRUE;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi break;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi last = current;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi current = current->sip_timeout_next;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi /*
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Check if this is in the to-be scheduled list
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (!ret && timeout_list != NULL) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi last = NULL;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi current = timeout_list;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi while (current != NULL) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (current->sip_timeout_id == id) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (current == timeout_list) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timeout_list =
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi current->sip_timeout_next;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi } else {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi last->sip_timeout_next =
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi current->sip_timeout_next;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (current->sip_timeout_callback_func_arg !=
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi NULL) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi free(current->
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_timeout_callback_func_arg);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi current->sip_timeout_callback_func_arg =
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi NULL;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi free(current);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi ret = B_TRUE;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi break;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi last = current;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi current = current->sip_timeout_next;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) pthread_mutex_unlock(&timeout_mutex);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi return (ret);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi}
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi/*
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Add a new timeout
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331viuint_t
40cb5e5daa7b80bb70fcf8dadfb20f9281566331visip_timeout(void *arg, void (*callback_func)(void *),
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi struct timeval *timeout_time)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi{
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_timeout_t *new_timeout;
2c2c41837e330b002c4220a39638150db504fe0evi sip_timeout_t *current;
2c2c41837e330b002c4220a39638150db504fe0evi sip_timeout_t *last;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi hrtime_t future_time;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi uint_t tid;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#ifdef __linux__
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi struct timespec tspec;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi hrtime_t now;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#endif
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi new_timeout = malloc(sizeof (sip_timeout_t));
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (new_timeout == NULL)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi return (0);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#ifdef __linux__
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (clock_gettime(CLOCK_REALTIME, &tspec) != 0)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi return (0);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi now = (hrtime_t)tspec.tv_sec * (hrtime_t)NANOSEC + tspec.tv_nsec;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi future_time = (hrtime_t)timeout_time->tv_sec * (hrtime_t)NANOSEC +
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (hrtime_t)(timeout_time->tv_usec * MILLISEC) + now;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#else
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi future_time = (hrtime_t)timeout_time->tv_sec * (hrtime_t)NANOSEC +
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (hrtime_t)(timeout_time->tv_usec * MILLISEC) + gethrtime();
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#endif
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (future_time <= 0L) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi free(new_timeout);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi return (0);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi new_timeout->sip_timeout_next = NULL;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi new_timeout->sip_timeout_val = future_time;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi new_timeout->sip_timeout_callback_func = callback_func;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi new_timeout->sip_timeout_callback_func_arg = arg;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) pthread_mutex_lock(&timeout_mutex);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timer_id++;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (timer_id == 0)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timer_id++;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi tid = timer_id;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi new_timeout->sip_timeout_id = tid;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi last = current = timeout_list;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi while (current != NULL) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (current->sip_timeout_val <= new_timeout->sip_timeout_val) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi last = current;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi current = current->sip_timeout_next;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi } else {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi break;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (current == timeout_list) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi new_timeout->sip_timeout_next = timeout_list;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timeout_list = new_timeout;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi } else {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi new_timeout->sip_timeout_next = current,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi last->sip_timeout_next = new_timeout;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) pthread_cond_signal(&timeout_cond_var);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) pthread_mutex_unlock(&timeout_mutex);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi return (tid);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi}
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi/*
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Schedule the next timeout
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vistatic hrtime_t
40cb5e5daa7b80bb70fcf8dadfb20f9281566331visip_schedule_to_functions()
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi{
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_timeout_t *timeout = NULL;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi sip_timeout_t *last = NULL;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi boolean_t create_thread = B_FALSE;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi hrtime_t current_time;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#ifdef __linux__
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi struct timespec tspec;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#endif
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi /*
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Thread is holding the mutex.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#ifdef __linux__
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (clock_gettime(CLOCK_REALTIME, &tspec) != 0)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi return ((hrtime_t)LONG_SLEEP_TIME + current_time);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi current_time = (hrtime_t)tspec.tv_sec * (hrtime_t)NANOSEC +
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi tspec.tv_nsec;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#else
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi current_time = gethrtime();
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#endif
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (timeout_list == NULL)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi return ((hrtime_t)LONG_SLEEP_TIME + current_time);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timeout = timeout_list;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi /*
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * Get all the timeouts that have fired.
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi while (timeout != NULL && timeout->sip_timeout_val <= current_time) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi last = timeout;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timeout = timeout->sip_timeout_next;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timeout = last;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (timeout != NULL) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (timeout_current_end != NULL) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timeout_current_end->sip_timeout_next = timeout_list;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timeout_current_end = timeout;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi } else {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timeout_current_start = timeout_list;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timeout_current_end = timeout;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi create_thread = B_TRUE;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timeout_list = timeout->sip_timeout_next;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timeout->sip_timeout_next = NULL;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (create_thread) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi pthread_t thr;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) pthread_create(&thr, NULL, sip_run_to_functions,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi NULL);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) pthread_detach(thr);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (timeout_list != NULL)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi return (timeout_list->sip_timeout_val);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi else
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi return ((hrtime_t)LONG_SLEEP_TIME + current_time);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi}
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi/*
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * The timer routine
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi/* ARGSUSED */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vistatic void *
40cb5e5daa7b80bb70fcf8dadfb20f9281566331visip_timer_thr(void *arg)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi{
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timestruc_t to;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi hrtime_t current_time;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi hrtime_t next_timeout;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi hrtime_t delta;
2c2c41837e330b002c4220a39638150db504fe0evi struct timeval tim;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#ifdef __linux__
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi struct timespec tspec;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#endif
2c2c41837e330b002c4220a39638150db504fe0evi delta = (hrtime_t)5 * NANOSEC;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) pthread_mutex_lock(&timeout_mutex);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi for (;;) {
2c2c41837e330b002c4220a39638150db504fe0evi (void) gettimeofday(&tim, NULL);
2c2c41837e330b002c4220a39638150db504fe0evi to.tv_sec = tim.tv_sec + (delta / NANOSEC);
2c2c41837e330b002c4220a39638150db504fe0evi to.tv_nsec = (hrtime_t)(tim.tv_usec * MILLISEC) +
2c2c41837e330b002c4220a39638150db504fe0evi (delta % NANOSEC);
2c2c41837e330b002c4220a39638150db504fe0evi if (to.tv_nsec > NANOSEC) {
2c2c41837e330b002c4220a39638150db504fe0evi to.tv_sec += (to.tv_nsec / NANOSEC);
2c2c41837e330b002c4220a39638150db504fe0evi to.tv_nsec %= NANOSEC;
2c2c41837e330b002c4220a39638150db504fe0evi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) pthread_cond_timedwait(&timeout_cond_var,
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi &timeout_mutex, &to);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi /*
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * We return from timedwait because we either timed out
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * or a new element was added and we need to reset the time
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331viagain:
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi next_timeout = sip_schedule_to_functions();
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#ifdef __linux__
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (clock_gettime(CLOCK_REALTIME, &tspec) != 0)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi goto again; /* ??? */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi current_time = (hrtime_t)tspec.tv_sec * (hrtime_t)NANOSEC +
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi tspec.tv_nsec;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#else
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi current_time = gethrtime();
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi#endif
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi delta = next_timeout - current_time;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (delta <= 0)
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi goto again;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi /* NOTREACHED */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi return ((void *)0);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi}
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi/*
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi * The init routine, starts the timer thread
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi */
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vivoid
40cb5e5daa7b80bb70fcf8dadfb20f9281566331visip_timeout_init()
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi{
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi static boolean_t timout_init = B_FALSE;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi pthread_t thread1;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) pthread_mutex_lock(&timeout_mutex);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi if (timout_init == B_FALSE) {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi timout_init = B_TRUE;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) pthread_mutex_unlock(&timeout_mutex);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi } else {
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) pthread_mutex_unlock(&timeout_mutex);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi return;
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi }
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi (void) pthread_create(&thread1, NULL, sip_timer_thr, NULL);
40cb5e5daa7b80bb70fcf8dadfb20f9281566331vi}