Home | History | Annotate | Download | only in netinet
      1 /*-
      2  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
      3  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
      4  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions are met:
      8  *
      9  * a) Redistributions of source code must retain the above copyright notice,
     10  *    this list of conditions and the following disclaimer.
     11  *
     12  * b) Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in
     14  *    the documentation and/or other materials provided with the distribution.
     15  *
     16  * c) Neither the name of Cisco Systems, Inc. nor the names of its
     17  *    contributors may be used to endorse or promote products derived
     18  *    from this software without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     30  * THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <netinet/sctp_os.h>
     34 #include <netinet/sctp_callout.h>
     35 #include <netinet/sctp_pcb.h>
     36 
     37 /*
     38  * Callout/Timer routines for OS that doesn't have them
     39  */
     40 #if defined(__APPLE__) || defined(__Userspace__)
     41 int ticks = 0;
     42 #else
     43 extern int ticks;
     44 #endif
     45 
     46 /*
     47  * SCTP_TIMERQ_LOCK protects:
     48  * - SCTP_BASE_INFO(callqueue)
     49  * - sctp_os_timer_current: current timer in process
     50  * - sctp_os_timer_next: next timer to check
     51  */
     52 static sctp_os_timer_t *sctp_os_timer_current = NULL;
     53 static sctp_os_timer_t *sctp_os_timer_next = NULL;
     54 
     55 void
     56 sctp_os_timer_init(sctp_os_timer_t *c)
     57 {
     58 	bzero(c, sizeof(*c));
     59 }
     60 
     61 void
     62 sctp_os_timer_start(sctp_os_timer_t *c, int to_ticks, void (*ftn) (void *),
     63                     void *arg)
     64 {
     65 	/* paranoia */
     66 	if ((c == NULL) || (ftn == NULL))
     67 	    return;
     68 
     69 	SCTP_TIMERQ_LOCK();
     70 	/* check to see if we're rescheduling a timer */
     71 	if (c->c_flags & SCTP_CALLOUT_PENDING) {
     72 		if (c == sctp_os_timer_next) {
     73 			sctp_os_timer_next = TAILQ_NEXT(c, tqe);
     74 		}
     75 		TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe);
     76 		/*
     77 		 * part of the normal "stop a pending callout" process
     78 		 * is to clear the CALLOUT_ACTIVE and CALLOUT_PENDING
     79 		 * flags.  We don't bother since we are setting these
     80 		 * below and we still hold the lock.
     81 		 */
     82 	}
     83 
     84 	/*
     85 	 * We could unlock/splx here and lock/spl at the TAILQ_INSERT_TAIL,
     86 	 * but there's no point since doing this setup doesn't take much time.
     87 	 */
     88 	if (to_ticks <= 0)
     89 		to_ticks = 1;
     90 
     91 	c->c_arg = arg;
     92 	c->c_flags = (SCTP_CALLOUT_ACTIVE | SCTP_CALLOUT_PENDING);
     93 	c->c_func = ftn;
     94 	c->c_time = ticks + to_ticks;
     95 	TAILQ_INSERT_TAIL(&SCTP_BASE_INFO(callqueue), c, tqe);
     96 	SCTP_TIMERQ_UNLOCK();
     97 }
     98 
     99 int
    100 sctp_os_timer_stop(sctp_os_timer_t *c)
    101 {
    102 	SCTP_TIMERQ_LOCK();
    103 	/*
    104 	 * Don't attempt to delete a callout that's not on the queue.
    105 	 */
    106 	if (!(c->c_flags & SCTP_CALLOUT_PENDING)) {
    107 		c->c_flags &= ~SCTP_CALLOUT_ACTIVE;
    108 		SCTP_TIMERQ_UNLOCK();
    109 		return (0);
    110 	}
    111 	c->c_flags &= ~(SCTP_CALLOUT_ACTIVE | SCTP_CALLOUT_PENDING);
    112 	if (c == sctp_os_timer_next) {
    113 		sctp_os_timer_next = TAILQ_NEXT(c, tqe);
    114 	}
    115 	TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe);
    116 	SCTP_TIMERQ_UNLOCK();
    117 	return (1);
    118 }
    119 
    120 #if defined(__APPLE__)
    121 /*
    122  * For __APPLE__, use a single main timer at a faster resolution than
    123  * fastim.  The timer just calls this existing callout infrastructure.
    124  */
    125 #endif
    126 void
    127 sctp_timeout(void *arg SCTP_UNUSED)
    128 {
    129 	sctp_os_timer_t *c;
    130 	void (*c_func)(void *);
    131 	void *c_arg;
    132 
    133 	SCTP_TIMERQ_LOCK();
    134 #if defined(__APPLE__)
    135 	/* update our tick count */
    136 	ticks += SCTP_BASE_VAR(sctp_main_timer_ticks);
    137 #endif
    138 	c = TAILQ_FIRST(&SCTP_BASE_INFO(callqueue));
    139 	while (c) {
    140 		if (c->c_time <= ticks) {
    141 			sctp_os_timer_next = TAILQ_NEXT(c, tqe);
    142 			TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe);
    143 			c_func = c->c_func;
    144 			c_arg = c->c_arg;
    145 			c->c_flags &= ~SCTP_CALLOUT_PENDING;
    146 			sctp_os_timer_current = c;
    147 			SCTP_TIMERQ_UNLOCK();
    148 			c_func(c_arg);
    149 			SCTP_TIMERQ_LOCK();
    150 			sctp_os_timer_current = NULL;
    151 			c = sctp_os_timer_next;
    152 		} else {
    153 			c = TAILQ_NEXT(c, tqe);
    154 		}
    155 	}
    156 	sctp_os_timer_next = NULL;
    157 	SCTP_TIMERQ_UNLOCK();
    158 
    159 #if defined(__APPLE__)
    160 	/* restart the main timer */
    161 	sctp_start_main_timer();
    162 #endif
    163 }
    164