Line data Source code
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 : #if defined(__Userspace__)
34 : #include <sys/types.h>
35 : #if !defined (__Userspace_os_Windows)
36 : #include <sys/wait.h>
37 : #include <unistd.h>
38 : #include <pthread.h>
39 : #endif
40 : #if defined(__Userspace_os_NaCl)
41 : #include <sys/select.h>
42 : #endif
43 : #include <stdlib.h>
44 : #include <string.h>
45 : #include <stdio.h>
46 : #include <errno.h>
47 : #include <netinet/sctp_sysctl.h>
48 : #include <netinet/sctp_pcb.h>
49 : #else
50 : #include <netinet/sctp_os.h>
51 : #include <netinet/sctp_callout.h>
52 : #include <netinet/sctp_pcb.h>
53 : #endif
54 :
55 : /*
56 : * Callout/Timer routines for OS that doesn't have them
57 : */
58 : #if defined(__APPLE__) || defined(__Userspace__)
59 : int ticks = 0;
60 : #else
61 : extern int ticks;
62 : #endif
63 :
64 : /*
65 : * SCTP_TIMERQ_LOCK protects:
66 : * - SCTP_BASE_INFO(callqueue)
67 : * - sctp_os_timer_next: next timer to check
68 : */
69 : static sctp_os_timer_t *sctp_os_timer_next = NULL;
70 :
71 : void
72 0 : sctp_os_timer_init(sctp_os_timer_t *c)
73 : {
74 0 : bzero(c, sizeof(*c));
75 0 : }
76 :
77 : void
78 0 : sctp_os_timer_start(sctp_os_timer_t *c, int to_ticks, void (*ftn) (void *),
79 : void *arg)
80 : {
81 : /* paranoia */
82 0 : if ((c == NULL) || (ftn == NULL))
83 0 : return;
84 :
85 0 : SCTP_TIMERQ_LOCK();
86 : /* check to see if we're rescheduling a timer */
87 0 : if (c->c_flags & SCTP_CALLOUT_PENDING) {
88 0 : if (c == sctp_os_timer_next) {
89 0 : sctp_os_timer_next = TAILQ_NEXT(c, tqe);
90 : }
91 0 : TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe);
92 : /*
93 : * part of the normal "stop a pending callout" process
94 : * is to clear the CALLOUT_ACTIVE and CALLOUT_PENDING
95 : * flags. We don't bother since we are setting these
96 : * below and we still hold the lock.
97 : */
98 : }
99 :
100 : /*
101 : * We could unlock/splx here and lock/spl at the TAILQ_INSERT_TAIL,
102 : * but there's no point since doing this setup doesn't take much time.
103 : */
104 0 : if (to_ticks <= 0)
105 0 : to_ticks = 1;
106 :
107 0 : c->c_arg = arg;
108 0 : c->c_flags = (SCTP_CALLOUT_ACTIVE | SCTP_CALLOUT_PENDING);
109 0 : c->c_func = ftn;
110 0 : c->c_time = ticks + to_ticks;
111 0 : TAILQ_INSERT_TAIL(&SCTP_BASE_INFO(callqueue), c, tqe);
112 0 : SCTP_TIMERQ_UNLOCK();
113 : }
114 :
115 : int
116 0 : sctp_os_timer_stop(sctp_os_timer_t *c)
117 : {
118 0 : SCTP_TIMERQ_LOCK();
119 : /*
120 : * Don't attempt to delete a callout that's not on the queue.
121 : */
122 0 : if (!(c->c_flags & SCTP_CALLOUT_PENDING)) {
123 0 : c->c_flags &= ~SCTP_CALLOUT_ACTIVE;
124 0 : SCTP_TIMERQ_UNLOCK();
125 0 : return (0);
126 : }
127 0 : c->c_flags &= ~(SCTP_CALLOUT_ACTIVE | SCTP_CALLOUT_PENDING);
128 0 : if (c == sctp_os_timer_next) {
129 0 : sctp_os_timer_next = TAILQ_NEXT(c, tqe);
130 : }
131 0 : TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe);
132 0 : SCTP_TIMERQ_UNLOCK();
133 0 : return (1);
134 : }
135 :
136 : static void
137 0 : sctp_handle_tick(int delta)
138 : {
139 : sctp_os_timer_t *c;
140 : void (*c_func)(void *);
141 : void *c_arg;
142 :
143 0 : SCTP_TIMERQ_LOCK();
144 : /* update our tick count */
145 0 : ticks += delta;
146 0 : c = TAILQ_FIRST(&SCTP_BASE_INFO(callqueue));
147 0 : while (c) {
148 0 : if (c->c_time <= ticks) {
149 0 : sctp_os_timer_next = TAILQ_NEXT(c, tqe);
150 0 : TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe);
151 0 : c_func = c->c_func;
152 0 : c_arg = c->c_arg;
153 0 : c->c_flags &= ~SCTP_CALLOUT_PENDING;
154 0 : SCTP_TIMERQ_UNLOCK();
155 0 : c_func(c_arg);
156 0 : SCTP_TIMERQ_LOCK();
157 0 : c = sctp_os_timer_next;
158 : } else {
159 0 : c = TAILQ_NEXT(c, tqe);
160 : }
161 : }
162 0 : sctp_os_timer_next = NULL;
163 0 : SCTP_TIMERQ_UNLOCK();
164 0 : }
165 :
166 : #if defined(__APPLE__)
167 : void
168 : sctp_timeout(void *arg SCTP_UNUSED)
169 : {
170 : sctp_handle_tick(SCTP_BASE_VAR(sctp_main_timer_ticks));
171 : sctp_start_main_timer();
172 : }
173 : #endif
174 :
175 : #if defined(__Userspace__)
176 : #define TIMEOUT_INTERVAL 10
177 :
178 : void *
179 0 : user_sctp_timer_iterate(void *arg)
180 : {
181 0 : for (;;) {
182 : #if defined (__Userspace_os_Windows)
183 : Sleep(TIMEOUT_INTERVAL);
184 : #else
185 : struct timeval timeout;
186 :
187 0 : timeout.tv_sec = 0;
188 0 : timeout.tv_usec = 1000 * TIMEOUT_INTERVAL;
189 0 : select(0, NULL, NULL, NULL, &timeout);
190 : #endif
191 0 : if (SCTP_BASE_VAR(timer_thread_should_exit)) {
192 0 : break;
193 : }
194 0 : sctp_handle_tick(MSEC_TO_TICKS(TIMEOUT_INTERVAL));
195 : }
196 0 : return (NULL);
197 : }
198 :
199 : void
200 0 : sctp_start_timer(void)
201 : {
202 : /*
203 : * No need to do SCTP_TIMERQ_LOCK_INIT();
204 : * here, it is being done in sctp_pcb_init()
205 : */
206 : #if defined (__Userspace_os_Windows)
207 : if ((SCTP_BASE_VAR(timer_thread) = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)user_sctp_timer_iterate, NULL, 0, NULL)) == NULL) {
208 : SCTP_PRINTF("ERROR; Creating ithread failed\n");
209 : }
210 : #else
211 : int rc;
212 :
213 0 : rc = pthread_create(&SCTP_BASE_VAR(timer_thread), NULL, user_sctp_timer_iterate, NULL);
214 0 : if (rc) {
215 0 : SCTP_PRINTF("ERROR; return code from pthread_create() is %d\n", rc);
216 : }
217 : #endif
218 0 : }
219 :
220 : #endif
|