1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/sctp/src/netinet/sctp_callout.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,224 @@ 1.4 +/*- 1.5 + * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. 1.6 + * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. 1.7 + * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. 1.8 + * 1.9 + * Redistribution and use in source and binary forms, with or without 1.10 + * modification, are permitted provided that the following conditions are met: 1.11 + * 1.12 + * a) Redistributions of source code must retain the above copyright notice, 1.13 + * this list of conditions and the following disclaimer. 1.14 + * 1.15 + * b) Redistributions in binary form must reproduce the above copyright 1.16 + * notice, this list of conditions and the following disclaimer in 1.17 + * the documentation and/or other materials provided with the distribution. 1.18 + * 1.19 + * c) Neither the name of Cisco Systems, Inc. nor the names of its 1.20 + * contributors may be used to endorse or promote products derived 1.21 + * from this software without specific prior written permission. 1.22 + * 1.23 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.24 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 1.25 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.26 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 1.27 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.28 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.29 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1.30 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1.31 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1.32 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 1.33 + * THE POSSIBILITY OF SUCH DAMAGE. 1.34 + */ 1.35 + 1.36 +#if defined(__Userspace__) 1.37 +#include <sys/types.h> 1.38 +#if !defined (__Userspace_os_Windows) 1.39 +#include <sys/wait.h> 1.40 +#include <unistd.h> 1.41 +#include <pthread.h> 1.42 +#endif 1.43 +#if defined(__Userspace_os_NaCl) 1.44 +#include <sys/select.h> 1.45 +#endif 1.46 +#include <stdlib.h> 1.47 +#include <string.h> 1.48 +#include <stdio.h> 1.49 +#include <errno.h> 1.50 +#include <netinet/sctp_sysctl.h> 1.51 +#include <netinet/sctp_pcb.h> 1.52 +#else 1.53 +#include <netinet/sctp_os.h> 1.54 +#include <netinet/sctp_callout.h> 1.55 +#include <netinet/sctp_pcb.h> 1.56 +#endif 1.57 + 1.58 +/* 1.59 + * Callout/Timer routines for OS that doesn't have them 1.60 + */ 1.61 +#if defined(__APPLE__) || defined(__Userspace__) 1.62 +int ticks = 0; 1.63 +#else 1.64 +extern int ticks; 1.65 +#endif 1.66 + 1.67 +/* 1.68 + * SCTP_TIMERQ_LOCK protects: 1.69 + * - SCTP_BASE_INFO(callqueue) 1.70 + * - sctp_os_timer_current: current timer in process 1.71 + * - sctp_os_timer_next: next timer to check 1.72 + */ 1.73 +static sctp_os_timer_t *sctp_os_timer_current = NULL; 1.74 +static sctp_os_timer_t *sctp_os_timer_next = NULL; 1.75 + 1.76 +void 1.77 +sctp_os_timer_init(sctp_os_timer_t *c) 1.78 +{ 1.79 + bzero(c, sizeof(*c)); 1.80 +} 1.81 + 1.82 +void 1.83 +sctp_os_timer_start(sctp_os_timer_t *c, int to_ticks, void (*ftn) (void *), 1.84 + void *arg) 1.85 +{ 1.86 + /* paranoia */ 1.87 + if ((c == NULL) || (ftn == NULL)) 1.88 + return; 1.89 + 1.90 + SCTP_TIMERQ_LOCK(); 1.91 + /* check to see if we're rescheduling a timer */ 1.92 + if (c->c_flags & SCTP_CALLOUT_PENDING) { 1.93 + if (c == sctp_os_timer_next) { 1.94 + sctp_os_timer_next = TAILQ_NEXT(c, tqe); 1.95 + } 1.96 + TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe); 1.97 + /* 1.98 + * part of the normal "stop a pending callout" process 1.99 + * is to clear the CALLOUT_ACTIVE and CALLOUT_PENDING 1.100 + * flags. We don't bother since we are setting these 1.101 + * below and we still hold the lock. 1.102 + */ 1.103 + } 1.104 + 1.105 + /* 1.106 + * We could unlock/splx here and lock/spl at the TAILQ_INSERT_TAIL, 1.107 + * but there's no point since doing this setup doesn't take much time. 1.108 + */ 1.109 + if (to_ticks <= 0) 1.110 + to_ticks = 1; 1.111 + 1.112 + c->c_arg = arg; 1.113 + c->c_flags = (SCTP_CALLOUT_ACTIVE | SCTP_CALLOUT_PENDING); 1.114 + c->c_func = ftn; 1.115 + c->c_time = ticks + to_ticks; 1.116 + TAILQ_INSERT_TAIL(&SCTP_BASE_INFO(callqueue), c, tqe); 1.117 + SCTP_TIMERQ_UNLOCK(); 1.118 +} 1.119 + 1.120 +int 1.121 +sctp_os_timer_stop(sctp_os_timer_t *c) 1.122 +{ 1.123 + SCTP_TIMERQ_LOCK(); 1.124 + /* 1.125 + * Don't attempt to delete a callout that's not on the queue. 1.126 + */ 1.127 + if (!(c->c_flags & SCTP_CALLOUT_PENDING)) { 1.128 + c->c_flags &= ~SCTP_CALLOUT_ACTIVE; 1.129 + SCTP_TIMERQ_UNLOCK(); 1.130 + return (0); 1.131 + } 1.132 + c->c_flags &= ~(SCTP_CALLOUT_ACTIVE | SCTP_CALLOUT_PENDING); 1.133 + if (c == sctp_os_timer_next) { 1.134 + sctp_os_timer_next = TAILQ_NEXT(c, tqe); 1.135 + } 1.136 + TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe); 1.137 + SCTP_TIMERQ_UNLOCK(); 1.138 + return (1); 1.139 +} 1.140 + 1.141 +static void 1.142 +sctp_handle_tick(int delta) 1.143 +{ 1.144 + sctp_os_timer_t *c; 1.145 + void (*c_func)(void *); 1.146 + void *c_arg; 1.147 + 1.148 + SCTP_TIMERQ_LOCK(); 1.149 + /* update our tick count */ 1.150 + ticks += delta; 1.151 + c = TAILQ_FIRST(&SCTP_BASE_INFO(callqueue)); 1.152 + while (c) { 1.153 + if (c->c_time <= ticks) { 1.154 + sctp_os_timer_next = TAILQ_NEXT(c, tqe); 1.155 + TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe); 1.156 + c_func = c->c_func; 1.157 + c_arg = c->c_arg; 1.158 + c->c_flags &= ~SCTP_CALLOUT_PENDING; 1.159 + sctp_os_timer_current = c; 1.160 + SCTP_TIMERQ_UNLOCK(); 1.161 + c_func(c_arg); 1.162 + SCTP_TIMERQ_LOCK(); 1.163 + sctp_os_timer_current = NULL; 1.164 + c = sctp_os_timer_next; 1.165 + } else { 1.166 + c = TAILQ_NEXT(c, tqe); 1.167 + } 1.168 + } 1.169 + sctp_os_timer_next = NULL; 1.170 + SCTP_TIMERQ_UNLOCK(); 1.171 +} 1.172 + 1.173 +#if defined(__APPLE__) 1.174 +void 1.175 +sctp_timeout(void *arg SCTP_UNUSED) 1.176 +{ 1.177 + sctp_handle_tick(SCTP_BASE_VAR(sctp_main_timer_ticks)); 1.178 + sctp_start_main_timer(); 1.179 +} 1.180 +#endif 1.181 + 1.182 +#if defined(__Userspace__) 1.183 +#define TIMEOUT_INTERVAL 10 1.184 + 1.185 +void * 1.186 +user_sctp_timer_iterate(void *arg) 1.187 +{ 1.188 + for (;;) { 1.189 +#if defined (__Userspace_os_Windows) 1.190 + Sleep(TIMEOUT_INTERVAL); 1.191 +#else 1.192 + struct timeval timeout; 1.193 + 1.194 + timeout.tv_sec = 0; 1.195 + timeout.tv_usec = 1000 * TIMEOUT_INTERVAL; 1.196 + select(0, NULL, NULL, NULL, &timeout); 1.197 +#endif 1.198 + if (SCTP_BASE_VAR(timer_thread_should_exit)) { 1.199 + break; 1.200 + } 1.201 + sctp_handle_tick(MSEC_TO_TICKS(TIMEOUT_INTERVAL)); 1.202 + } 1.203 + return (NULL); 1.204 +} 1.205 + 1.206 +void 1.207 +sctp_start_timer(void) 1.208 +{ 1.209 + /* 1.210 + * No need to do SCTP_TIMERQ_LOCK_INIT(); 1.211 + * here, it is being done in sctp_pcb_init() 1.212 + */ 1.213 +#if defined (__Userspace_os_Windows) 1.214 + if ((SCTP_BASE_VAR(timer_thread) = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)user_sctp_timer_iterate, NULL, 0, NULL)) == NULL) { 1.215 + SCTP_PRINTF("ERROR; Creating ithread failed\n"); 1.216 + } 1.217 +#else 1.218 + int rc; 1.219 + 1.220 + rc = pthread_create(&SCTP_BASE_VAR(timer_thread), NULL, user_sctp_timer_iterate, NULL); 1.221 + if (rc) { 1.222 + SCTP_PRINTF("ERROR; return code from pthread_create() is %d\n", rc); 1.223 + } 1.224 +#endif 1.225 +} 1.226 + 1.227 +#endif