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
45u32_t lwip_sys_now;
46
47u32_t
48sys_jiffies(void)
49{
50  return lwip_sys_now;
51}
52
53u32_t
54sys_now(void)
55{
56  return lwip_sys_now;
57}
58
59void
60sys_init(void)
61{
62}
63
64#if !NO_SYS
65
66test_sys_arch_waiting_fn the_waiting_fn;
67
68void
69test_sys_arch_wait_callback(test_sys_arch_waiting_fn waiting_fn)
70{
71  the_waiting_fn = waiting_fn;
72}
73
74err_t
75sys_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
82void
83sys_sem_free(sys_sem_t *sem)
84{
85  LWIP_ASSERT("sem != NULL", sem != NULL);
86  *sem = 0;
87}
88
89void
90sys_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 */
97u32_t
98sys_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
139void
140sys_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
148err_t
149sys_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
156void
157sys_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
165void
166sys_mutex_set_invalid(sys_mutex_t *mutex)
167{
168  LWIP_ASSERT("mutex != NULL", mutex != NULL);
169  *mutex = 0;
170}
171
172void
173sys_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
184void
185sys_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
196sys_thread_t
197sys_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
208err_t
209sys_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
227void
228sys_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
240void
241sys_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
249void
250sys_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
269err_t
270sys_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
286err_t
287sys_mbox_trypost_fromisr(sys_mbox_t *q, void *msg)
288{
289  return sys_mbox_trypost(q, msg);
290}
291
292u32_t
293sys_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
342u32_t
343sys_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#error LWIP_NETCONN_SEM_PER_THREAD==1 not supported
369#endif /* LWIP_NETCONN_SEM_PER_THREAD */
370
371#endif /* !NO_SYS */
372