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