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