1 /*
2 * Copyright (c) 2017 Simon Goldschmidt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
25 * OF SUCH DAMAGE.
26 *
27 * This file is part of the lwIP TCP/IP stack.
28 *
29 * Author: Simon Goldschmidt
30 *
31 */
32
33
34 #include <lwip/opt.h>
35 #include <lwip/arch.h>
36 #if !NO_SYS
37 #include "sys_arch.h"
38 #endif
39 #include <lwip/stats.h>
40 #include <lwip/debug.h>
41 #include <lwip/sys.h>
42
43 #include <string.h>
44
45 u32_t lwip_sys_now;
46
47 u32_t
sys_jiffies(void)48 sys_jiffies(void)
49 {
50 return lwip_sys_now;
51 }
52
53 u32_t
sys_now(void)54 sys_now(void)
55 {
56 return lwip_sys_now;
57 }
58
59 void
sys_init(void)60 sys_init(void)
61 {
62 }
63
64 #if !NO_SYS
65
66 test_sys_arch_waiting_fn the_waiting_fn;
67
68 void
test_sys_arch_wait_callback(test_sys_arch_waiting_fn waiting_fn)69 test_sys_arch_wait_callback(test_sys_arch_waiting_fn waiting_fn)
70 {
71 the_waiting_fn = waiting_fn;
72 }
73
74 err_t
sys_sem_new(sys_sem_t * sem,u8_t count)75 sys_sem_new(sys_sem_t *sem, u8_t count)
76 {
77 LWIP_ASSERT("sem != NULL", sem != NULL);
78 *sem = count + 1;
79 return ERR_OK;
80 }
81
82 void
sys_sem_free(sys_sem_t * sem)83 sys_sem_free(sys_sem_t *sem)
84 {
85 LWIP_ASSERT("sem != NULL", sem != NULL);
86 *sem = 0;
87 }
88
89 void
sys_sem_set_invalid(sys_sem_t * sem)90 sys_sem_set_invalid(sys_sem_t *sem)
91 {
92 LWIP_ASSERT("sem != NULL", sem != NULL);
93 *sem = 0;
94 }
95
96 /* semaphores are 1-based because RAM is initialized as 0, which would be valid */
97 u32_t
sys_arch_sem_wait(sys_sem_t * sem,u32_t timeout)98 sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
99 {
100 u32_t ret = 0;
101 LWIP_ASSERT("sem != NULL", sem != NULL);
102 LWIP_ASSERT("*sem > 0", *sem > 0);
103 if (*sem == 1) {
104 /* need to wait */
105 if(!timeout)
106 {
107 /* wait infinite */
108 LWIP_ASSERT("cannot wait without waiting callback", the_waiting_fn != NULL);
109 do {
110 int expectSomething = the_waiting_fn(sem, NULL);
111 LWIP_ASSERT("*sem > 0", *sem > 0);
112 LWIP_ASSERT("expecting a semaphore count but it's 0", !expectSomething || (*sem > 1));
113 ret++;
114 if (ret == SYS_ARCH_TIMEOUT) {
115 ret--;
116 }
117 } while(*sem == 1);
118 }
119 else
120 {
121 if (the_waiting_fn) {
122 int expectSomething = the_waiting_fn(sem, NULL);
123 LWIP_ASSERT("expecting a semaphore count but it's 0", !expectSomething || (*sem > 1));
124 }
125 LWIP_ASSERT("*sem > 0", *sem > 0);
126 if (*sem == 1) {
127 return SYS_ARCH_TIMEOUT;
128 }
129 ret = 1;
130 }
131 }
132 LWIP_ASSERT("*sem > 0", *sem > 0);
133 (*sem)--;
134 LWIP_ASSERT("*sem > 0", *sem > 0);
135 /* return the time we waited for the sem */
136 return ret;
137 }
138
139 void
sys_sem_signal(sys_sem_t * sem)140 sys_sem_signal(sys_sem_t *sem)
141 {
142 LWIP_ASSERT("sem != NULL", sem != NULL);
143 LWIP_ASSERT("*sem > 0", *sem > 0);
144 (*sem)++;
145 LWIP_ASSERT("*sem > 0", *sem > 0);
146 }
147
148 err_t
sys_mutex_new(sys_mutex_t * mutex)149 sys_mutex_new(sys_mutex_t *mutex)
150 {
151 LWIP_ASSERT("mutex != NULL", mutex != NULL);
152 *mutex = 1; /* 1 allocated */
153 return ERR_OK;
154 }
155
156 void
sys_mutex_free(sys_mutex_t * mutex)157 sys_mutex_free(sys_mutex_t *mutex)
158 {
159 /* parameter check */
160 LWIP_ASSERT("mutex != NULL", mutex != NULL);
161 LWIP_ASSERT("*mutex >= 1", *mutex >= 1);
162 *mutex = 0;
163 }
164
165 void
sys_mutex_set_invalid(sys_mutex_t * mutex)166 sys_mutex_set_invalid(sys_mutex_t *mutex)
167 {
168 LWIP_ASSERT("mutex != NULL", mutex != NULL);
169 *mutex = 0;
170 }
171
172 void
sys_mutex_lock(sys_mutex_t * mutex)173 sys_mutex_lock(sys_mutex_t *mutex)
174 {
175 /* nothing to do, no multithreading supported */
176 LWIP_ASSERT("mutex != NULL", mutex != NULL);
177 /* check that the mutext is valid and unlocked (no nested locking) */
178 LWIP_ASSERT("*mutex >= 1", *mutex == 1);
179 /* we count up just to check the correct pairing of lock/unlock */
180 (*mutex)++;
181 LWIP_ASSERT("*mutex >= 1", *mutex >= 1);
182 }
183
184 void
sys_mutex_unlock(sys_mutex_t * mutex)185 sys_mutex_unlock(sys_mutex_t *mutex)
186 {
187 /* nothing to do, no multithreading supported */
188 LWIP_ASSERT("mutex != NULL", mutex != NULL);
189 LWIP_ASSERT("*mutex >= 1", *mutex >= 1);
190 /* we count down just to check the correct pairing of lock/unlock */
191 (*mutex)--;
192 LWIP_ASSERT("*mutex >= 1", *mutex >= 1);
193 }
194
195
196 sys_thread_t
sys_thread_new(const char * name,lwip_thread_fn function,void * arg,int stacksize,int prio)197 sys_thread_new(const char *name, lwip_thread_fn function, void *arg, int stacksize, int prio)
198 {
199 LWIP_UNUSED_ARG(name);
200 LWIP_UNUSED_ARG(function);
201 LWIP_UNUSED_ARG(arg);
202 LWIP_UNUSED_ARG(stacksize);
203 LWIP_UNUSED_ARG(prio);
204 /* threads not supported */
205 return 0;
206 }
207
208 err_t
sys_mbox_new(sys_mbox_t * mbox,int size)209 sys_mbox_new(sys_mbox_t *mbox, int size)
210 {
211 int mboxsize = size;
212 LWIP_ASSERT("mbox != NULL", mbox != NULL);
213 LWIP_ASSERT("size >= 0", size >= 0);
214 if (size == 0) {
215 mboxsize = 1024;
216 }
217 mbox->head = mbox->tail = 0;
218 mbox->sem = mbox; /* just point to something for sys_mbox_valid() */
219 mbox->q_mem = (void**)malloc(sizeof(void*)*mboxsize);
220 mbox->size = mboxsize;
221 mbox->used = 0;
222
223 memset(mbox->q_mem, 0, sizeof(void*)*mboxsize);
224 return ERR_OK;
225 }
226
227 void
sys_mbox_free(sys_mbox_t * mbox)228 sys_mbox_free(sys_mbox_t *mbox)
229 {
230 /* parameter check */
231 LWIP_ASSERT("mbox != NULL", mbox != NULL);
232 LWIP_ASSERT("mbox->sem != NULL", mbox->sem != NULL);
233 LWIP_ASSERT("mbox->sem == mbox", mbox->sem == mbox);
234 LWIP_ASSERT("mbox->q_mem != NULL", mbox->q_mem != NULL);
235 mbox->sem = NULL;
236 free(mbox->q_mem);
237 mbox->q_mem = NULL;
238 }
239
240 void
sys_mbox_set_invalid(sys_mbox_t * mbox)241 sys_mbox_set_invalid(sys_mbox_t *mbox)
242 {
243 LWIP_ASSERT("mbox != NULL", mbox != NULL);
244 LWIP_ASSERT("mbox->q_mem == NULL", mbox->q_mem == NULL);
245 mbox->sem = NULL;
246 mbox->q_mem = NULL;
247 }
248
249 void
sys_mbox_post(sys_mbox_t * q,void * msg)250 sys_mbox_post(sys_mbox_t *q, void *msg)
251 {
252 LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL);
253 LWIP_ASSERT("q->sem == q", q->sem == q);
254 LWIP_ASSERT("q->q_mem != NULL", q->q_mem != NULL);
255 LWIP_ASSERT("q->used >= 0", q->used >= 0);
256 LWIP_ASSERT("q->size > 0", q->size > 0);
257
258 LWIP_ASSERT("mbox already full", q->used < q->size);
259
260 q->q_mem[q->head] = msg;
261 q->head++;
262 if (q->head >= (unsigned int)q->size) {
263 q->head = 0;
264 }
265 LWIP_ASSERT("mbox is full!", q->head != q->tail);
266 q->used++;
267 }
268
269 err_t
sys_mbox_trypost(sys_mbox_t * q,void * msg)270 sys_mbox_trypost(sys_mbox_t *q, void *msg)
271 {
272 LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL);
273 LWIP_ASSERT("q->sem == q", q->sem == q);
274 LWIP_ASSERT("q->q_mem != NULL", q->q_mem != NULL);
275 LWIP_ASSERT("q->used >= 0", q->used >= 0);
276 LWIP_ASSERT("q->size > 0", q->size > 0);
277 LWIP_ASSERT("q->used <= q->size", q->used <= q->size);
278
279 if (q->used == q->size) {
280 return ERR_MEM;
281 }
282 sys_mbox_post(q, msg);
283 return ERR_OK;
284 }
285
286 err_t
sys_mbox_trypost_fromisr(sys_mbox_t * q,void * msg)287 sys_mbox_trypost_fromisr(sys_mbox_t *q, void *msg)
288 {
289 return sys_mbox_trypost(q, msg);
290 }
291
292 u32_t
sys_arch_mbox_fetch(sys_mbox_t * q,void ** msg,u32_t timeout)293 sys_arch_mbox_fetch(sys_mbox_t *q, void **msg, u32_t timeout)
294 {
295 u32_t ret = 0;
296 u32_t ret2;
297 LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL);
298 LWIP_ASSERT("q->sem == q", q->sem == q);
299 LWIP_ASSERT("q->q_mem != NULL", q->q_mem != NULL);
300 LWIP_ASSERT("q->used >= 0", q->used >= 0);
301 LWIP_ASSERT("q->size > 0", q->size > 0);
302
303 if (q->used == 0) {
304 /* need to wait */
305 /* need to wait */
306 if(!timeout)
307 {
308 /* wait infinite */
309 LWIP_ASSERT("cannot wait without waiting callback", the_waiting_fn != NULL);
310 do {
311 int expectSomething = the_waiting_fn(NULL, q);
312 LWIP_ASSERT("q->used >= 0", q->used >= 0);
313 LWIP_ASSERT("expecting item available but it's 0", !expectSomething || (q->used > 0));
314 ret++;
315 if (ret == SYS_ARCH_TIMEOUT) {
316 ret--;
317 }
318 } while(q->used == 0);
319 }
320 else
321 {
322 if (the_waiting_fn) {
323 int expectSomething = the_waiting_fn(NULL, q);
324 LWIP_ASSERT("expecting item available count but it's 0", !expectSomething || (q->used > 0));
325 }
326 LWIP_ASSERT("q->used >= 0", q->used >= 0);
327 if (q->used == 0) {
328 if(msg) {
329 *msg = NULL;
330 }
331 return SYS_ARCH_TIMEOUT;
332 }
333 ret = 1;
334 }
335 }
336 LWIP_ASSERT("q->used > 0", q->used > 0);
337 ret2 = sys_arch_mbox_tryfetch(q, msg);
338 LWIP_ASSERT("got no message", ret2 == 0);
339 return ret;
340 }
341
342 u32_t
sys_arch_mbox_tryfetch(sys_mbox_t * q,void ** msg)343 sys_arch_mbox_tryfetch(sys_mbox_t *q, void **msg)
344 {
345 LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL);
346 LWIP_ASSERT("q->sem == q", q->sem == q);
347 LWIP_ASSERT("q->q_mem != NULL", q->q_mem != NULL);
348 LWIP_ASSERT("q->used >= 0", q->used >= 0);
349 LWIP_ASSERT("q->size > 0", q->size > 0);
350
351 if (!q->used) {
352 return SYS_ARCH_TIMEOUT;
353 }
354 if(msg) {
355 *msg = q->q_mem[q->tail];
356 }
357
358 q->tail++;
359 if (q->tail >= (unsigned int)q->size) {
360 q->tail = 0;
361 }
362 q->used--;
363 LWIP_ASSERT("q->used >= 0", q->used >= 0);
364 return 0;
365 }
366
367 #if LWIP_NETCONN_SEM_PER_THREAD
368 /* Simple implementation of this: unit tests only support one thread */
369 static sys_sem_t global_netconn_sem;
370
sys_arch_netconn_sem_get(void)371 sys_sem_t* sys_arch_netconn_sem_get(void)
372 {
373 return &global_netconn_sem;
374 }
375
sys_arch_netconn_sem_alloc(void)376 void sys_arch_netconn_sem_alloc(void)
377 {
378 sys_sem_new(&global_netconn_sem, 0);
379 }
380
sys_arch_netconn_sem_free(void)381 void sys_arch_netconn_sem_free(void)
382 {
383 sys_sem_free(&global_netconn_sem);
384 }
385 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
386
387 #endif /* !NO_SYS */
388