/src/usrsctp/usrsctplib/netinet/sctp_callout.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*- |
2 | | * SPDX-License-Identifier: BSD-3-Clause |
3 | | * |
4 | | * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. |
5 | | * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. |
6 | | * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. |
7 | | * |
8 | | * Redistribution and use in source and binary forms, with or without |
9 | | * modification, are permitted provided that the following conditions are met: |
10 | | * |
11 | | * a) Redistributions of source code must retain the above copyright notice, |
12 | | * this list of conditions and the following disclaimer. |
13 | | * |
14 | | * b) Redistributions in binary form must reproduce the above copyright |
15 | | * notice, this list of conditions and the following disclaimer in |
16 | | * the documentation and/or other materials provided with the distribution. |
17 | | * |
18 | | * c) Neither the name of Cisco Systems, Inc. nor the names of its |
19 | | * contributors may be used to endorse or promote products derived |
20 | | * from this software without specific prior written permission. |
21 | | * |
22 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
23 | | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
24 | | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
26 | | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
27 | | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
28 | | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
29 | | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
30 | | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
31 | | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
32 | | * THE POSSIBILITY OF SUCH DAMAGE. |
33 | | */ |
34 | | |
35 | | #if defined(__Userspace__) |
36 | | #include <sys/types.h> |
37 | | #if !defined(_WIN32) |
38 | | #include <sys/wait.h> |
39 | | #include <unistd.h> |
40 | | #include <pthread.h> |
41 | | #endif |
42 | | #if defined(__native_client__) |
43 | | #include <sys/select.h> |
44 | | #endif |
45 | | #include <stdlib.h> |
46 | | #include <string.h> |
47 | | #include <stdio.h> |
48 | | #include <errno.h> |
49 | | #include <user_atomic.h> |
50 | | #include <netinet/sctp_sysctl.h> |
51 | | #include <netinet/sctp_pcb.h> |
52 | | #else |
53 | | #include <netinet/sctp_os.h> |
54 | | #include <netinet/sctp_callout.h> |
55 | | #include <netinet/sctp_pcb.h> |
56 | | #endif |
57 | | #include <netinet/sctputil.h> |
58 | | |
59 | | /* |
60 | | * Callout/Timer routines for OS that doesn't have them |
61 | | */ |
62 | | #if defined(__APPLE__) || defined(__Userspace__) |
63 | | static uint32_t ticks = 0; |
64 | | #else |
65 | | extern int ticks; |
66 | | #endif |
67 | | |
68 | 191k | uint32_t sctp_get_tick_count(void) { |
69 | 191k | uint32_t ret; |
70 | | |
71 | 191k | SCTP_TIMERQ_LOCK(); |
72 | 191k | ret = ticks; |
73 | 191k | SCTP_TIMERQ_UNLOCK(); |
74 | 191k | return ret; |
75 | 191k | } |
76 | | |
77 | | /* |
78 | | * SCTP_TIMERQ_LOCK protects: |
79 | | * - SCTP_BASE_INFO(callqueue) |
80 | | * - sctp_os_timer_next: next timer to check |
81 | | */ |
82 | | static sctp_os_timer_t *sctp_os_timer_next = NULL; |
83 | | |
84 | | void |
85 | | sctp_os_timer_init(sctp_os_timer_t *c) |
86 | 312k | { |
87 | 312k | memset(c, 0, sizeof(*c)); |
88 | 312k | } |
89 | | |
90 | | int |
91 | | sctp_os_timer_start(sctp_os_timer_t *c, uint32_t to_ticks, void (*ftn) (void *), |
92 | | void *arg) |
93 | 191k | { |
94 | 191k | int ret = 0; |
95 | | |
96 | | /* paranoia */ |
97 | 191k | if ((c == NULL) || (ftn == NULL)) |
98 | 0 | return (ret); |
99 | | |
100 | 191k | SCTP_TIMERQ_LOCK(); |
101 | | /* check to see if we're rescheduling a timer */ |
102 | 191k | if (c->c_flags & SCTP_CALLOUT_PENDING) { |
103 | 0 | ret = 1; |
104 | 0 | if (c == sctp_os_timer_next) { |
105 | 0 | sctp_os_timer_next = TAILQ_NEXT(c, tqe); |
106 | 0 | } |
107 | 0 | TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe); |
108 | | /* |
109 | | * part of the normal "stop a pending callout" process |
110 | | * is to clear the CALLOUT_ACTIVE and CALLOUT_PENDING |
111 | | * flags. We don't bother since we are setting these |
112 | | * below and we still hold the lock. |
113 | | */ |
114 | 0 | } |
115 | | |
116 | | /* |
117 | | * We could unlock/splx here and lock/spl at the TAILQ_INSERT_TAIL, |
118 | | * but there's no point since doing this setup doesn't take much time. |
119 | | */ |
120 | 191k | if (to_ticks == 0) |
121 | 0 | to_ticks = 1; |
122 | | |
123 | 191k | c->c_arg = arg; |
124 | 191k | c->c_flags = (SCTP_CALLOUT_ACTIVE | SCTP_CALLOUT_PENDING); |
125 | 191k | c->c_func = ftn; |
126 | 191k | c->c_time = ticks + to_ticks; |
127 | 191k | TAILQ_INSERT_TAIL(&SCTP_BASE_INFO(callqueue), c, tqe); |
128 | 191k | SCTP_TIMERQ_UNLOCK(); |
129 | 191k | return (ret); |
130 | 191k | } |
131 | | |
132 | | int |
133 | | sctp_os_timer_stop(sctp_os_timer_t *c) |
134 | 484k | { |
135 | 484k | SCTP_TIMERQ_LOCK(); |
136 | | /* |
137 | | * Don't attempt to delete a callout that's not on the queue. |
138 | | */ |
139 | 484k | if ((c->c_flags & SCTP_CALLOUT_PENDING) == 0) { |
140 | 295k | c->c_flags &= ~SCTP_CALLOUT_ACTIVE; |
141 | 295k | SCTP_TIMERQ_UNLOCK(); |
142 | 295k | return (0); |
143 | 295k | } |
144 | 189k | c->c_flags &= ~(SCTP_CALLOUT_ACTIVE | SCTP_CALLOUT_PENDING); |
145 | 189k | if (c == sctp_os_timer_next) { |
146 | 0 | sctp_os_timer_next = TAILQ_NEXT(c, tqe); |
147 | 0 | } |
148 | 189k | TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe); |
149 | 189k | SCTP_TIMERQ_UNLOCK(); |
150 | 189k | return (1); |
151 | 189k | } |
152 | | |
153 | | void |
154 | | sctp_handle_tick(uint32_t elapsed_ticks) |
155 | 2.06k | { |
156 | 2.06k | sctp_os_timer_t *c; |
157 | 2.06k | void (*c_func)(void *); |
158 | 2.06k | void *c_arg; |
159 | | |
160 | 2.06k | SCTP_TIMERQ_LOCK(); |
161 | | /* update our tick count */ |
162 | 2.06k | ticks += elapsed_ticks; |
163 | 2.06k | c = TAILQ_FIRST(&SCTP_BASE_INFO(callqueue)); |
164 | 13.5k | while (c) { |
165 | 11.5k | if (SCTP_UINT32_GE(ticks, c->c_time)) { |
166 | 2.14k | sctp_os_timer_next = TAILQ_NEXT(c, tqe); |
167 | 2.14k | TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe); |
168 | 2.14k | c_func = c->c_func; |
169 | 2.14k | c_arg = c->c_arg; |
170 | 2.14k | c->c_flags &= ~SCTP_CALLOUT_PENDING; |
171 | 2.14k | SCTP_TIMERQ_UNLOCK(); |
172 | 2.14k | c_func(c_arg); |
173 | 2.14k | SCTP_TIMERQ_LOCK(); |
174 | 2.14k | c = sctp_os_timer_next; |
175 | 9.37k | } else { |
176 | 9.37k | c = TAILQ_NEXT(c, tqe); |
177 | 9.37k | } |
178 | 11.5k | } |
179 | 2.06k | sctp_os_timer_next = NULL; |
180 | 2.06k | SCTP_TIMERQ_UNLOCK(); |
181 | 2.06k | } |
182 | | |
183 | | #if defined(__APPLE__) && !defined(__Userspace__) |
184 | | void |
185 | | sctp_timeout(void *arg SCTP_UNUSED) |
186 | | { |
187 | | sctp_handle_tick(SCTP_BASE_VAR(sctp_main_timer_ticks)); |
188 | | sctp_start_main_timer(); |
189 | | } |
190 | | #endif |
191 | | |
192 | | #if defined(__Userspace__) |
193 | 4.13k | #define TIMEOUT_INTERVAL 10 |
194 | | |
195 | | void * |
196 | | user_sctp_timer_iterate(void *arg) |
197 | 3 | { |
198 | 3 | sctp_userspace_set_threadname("SCTP timer"); |
199 | 2.06k | for (;;) { |
200 | | #if defined(_WIN32) |
201 | | Sleep(TIMEOUT_INTERVAL); |
202 | | #else |
203 | 2.06k | struct timespec amount, remaining; |
204 | | |
205 | 2.06k | remaining.tv_sec = 0; |
206 | 2.06k | remaining.tv_nsec = TIMEOUT_INTERVAL * 1000 * 1000; |
207 | 2.06k | do { |
208 | 2.06k | amount = remaining; |
209 | 2.06k | } while (nanosleep(&amount, &remaining) == -1); |
210 | 2.06k | #endif |
211 | 2.06k | if (atomic_cmpset_int(&SCTP_BASE_VAR(timer_thread_should_exit), 1, 1)) { |
212 | 0 | break; |
213 | 0 | } |
214 | 2.06k | sctp_handle_tick(sctp_msecs_to_ticks(TIMEOUT_INTERVAL)); |
215 | 2.06k | } |
216 | 3 | return (NULL); |
217 | 3 | } |
218 | | |
219 | | void |
220 | | sctp_start_timer_thread(void) |
221 | 3 | { |
222 | | /* |
223 | | * No need to do SCTP_TIMERQ_LOCK_INIT(); |
224 | | * here, it is being done in sctp_pcb_init() |
225 | | */ |
226 | 3 | int rc; |
227 | | |
228 | 3 | rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(timer_thread), user_sctp_timer_iterate); |
229 | 3 | if (rc) { |
230 | 0 | SCTP_PRINTF("ERROR; return code from sctp_thread_create() is %d\n", rc); |
231 | 3 | } else { |
232 | 3 | SCTP_BASE_VAR(timer_thread_started) = 1; |
233 | 3 | } |
234 | 3 | } |
235 | | |
236 | | void |
237 | | sctp_stop_timer_thread(void) |
238 | 0 | { |
239 | 0 | atomic_cmpset_int(&SCTP_BASE_VAR(timer_thread_should_exit), 0, 1); |
240 | 0 | if (SCTP_BASE_VAR(timer_thread_started)) { |
241 | | #if defined(_WIN32) |
242 | | WaitForSingleObject(SCTP_BASE_VAR(timer_thread), INFINITE); |
243 | | CloseHandle(SCTP_BASE_VAR(timer_thread)); |
244 | | #else |
245 | 0 | pthread_join(SCTP_BASE_VAR(timer_thread), NULL); |
246 | 0 | #endif |
247 | 0 | } |
248 | 0 | } |
249 | | #endif |