• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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