• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * @file
3  * OS abstraction layer
4  */
5 
6 /*
7  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without modification,
11  * are permitted provided that the following conditions are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright notice,
14  *    this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  *    this list of conditions and the following disclaimer in the documentation
17  *    and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26  * OF 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) ARISING
29  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30  * OF SUCH DAMAGE.
31  *
32  * This file is part of the lwIP TCP/IP stack.
33  *
34  * Author: Adam Dunkels <adam@sics.se>
35  */
36 
37 #ifndef LWIP_HDR_SYS_H
38 #define LWIP_HDR_SYS_H
39 
40 #include "lwip/opt.h"
41 
42 #if defined (__cplusplus) && __cplusplus
43 extern "C" {
44 #endif
45 
46 #if NO_SYS
47 
48 /* For a totally minimal and standalone system, we provide null
49    definitions of the sys_ functions. */
50 typedef u8_t sys_sem_t;
51 typedef u8_t sys_mutex_t;
52 typedef u8_t sys_mbox_t;
53 typedef u8_t sys_dual_mbox_t;
54 
55 #define sys_sem_new(s, c) ERR_OK
56 #define sys_sem_signal(s)
57 #define sys_sem_wait(s)
58 #define sys_arch_sem_wait(s, t)
59 #define sys_sem_free(s)
60 #define sys_sem_valid(s) 0
61 #define sys_sem_valid_val(s) 0
62 #define sys_sem_set_invalid(s)
63 #define sys_sem_set_invalid_val(s)
64 #define sys_mutex_new(mu) ERR_OK
65 #define sys_mutex_lock(mu)
66 #define sys_mutex_unlock(mu)
67 #define sys_mutex_free(mu)
68 #define sys_mutex_valid(mu) 0
69 #define sys_mutex_set_invalid(mu)
70 #define sys_mbox_new(m, s) ERR_OK
71 #define sys_mbox_fetch(m, d)
72 #define sys_mbox_tryfetch(m, d)
73 #define sys_mbox_post(m, d)
74 #define sys_mbox_trypost(m, d)
75 #define sys_mbox_free(m)
76 #define sys_mbox_valid(m)
77 #define sys_mbox_valid_val(m)
78 #define sys_mbox_set_invalid(m)
79 #define sys_dual_mbox_valid(m)
80 #define sys_mbox_set_invalid_val(m)
81 
82 #define sys_dual_mbox_new(m, s) ERR_OK
83 #define sys_dual_mbox_fetch(m, d)
84 #define sys_dual_mbox_tryfetch(m, d)
85 #define sys_dual_mbox_post(m, d)
86 #define sys_dual_mbox_trypost(m, d)
87 #define sys_dual_mbox_post_priority(m, d)
88 #define sys_dual_mbox_free(m)
89 #define sys_dual_mbox_valid(m)
90 #define sys_dual_mbox_set_invalid(m)
91 
92 #define sys_thread_new(n, t, a, s, p)
93 
94 #define sys_msleep(t)
95 
96 /* Return code for Error from sys_thread_new and sys_arch_sem_wait */
97 #define SYS_ARCH_ERROR 0xffffffffU
98 
99 #else /* NO_SYS */
100 
101 /* Return code for Error from sys_thread_new and sys_arch_sem_wait */
102 #define SYS_ARCH_ERROR 0xffffffffU
103 
104 /* Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */
105 #define SYS_ARCH_TIMEOUT 0x7fffffffUL
106 
107 /* sys_mbox_tryfetch() returns SYS_MBOX_EMPTY if appropriate.
108  * For now we use the same magic value, but we allow this to change in future.
109  */
110 #define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT
111 
112 #include "lwip/err.h"
113 #include "arch/sys_arch.h"
114 
115 /* Function prototype for thread functions */
116 typedef void (*lwip_thread_fn)(void *arg);
117 
118 /* Function prototypes for functions to be implemented by platform ports
119    (in sys_arch.c) */
120 
121 /* Mutex functions: */
122 
123 /* Define LWIP_COMPAT_MUTEX if the port has no mutexes and binary semaphores
124     should be used instead */
125 #ifndef LWIP_COMPAT_MUTEX
126 #define LWIP_COMPAT_MUTEX 0
127 #endif
128 
129 #if LWIP_COMPAT_MUTEX
130 /* for old ports that don't have mutexes: define them to binary semaphores */
131 #define sys_mutex_t                   sys_sem_t
132 #define sys_mutex_new(mutex)          sys_sem_new(mutex, 1)
133 #define sys_mutex_lock(mutex)         sys_sem_wait(mutex)
134 #define sys_mutex_unlock(mutex)       sys_sem_signal(mutex)
135 #define sys_mutex_free(mutex)         sys_sem_free(mutex)
136 #define sys_mutex_valid(mutex)        sys_sem_valid(mutex)
137 #define sys_mutex_set_invalid(mutex)  sys_sem_set_invalid(mutex)
138 
139 #else /* LWIP_COMPAT_MUTEX */
140 
141 /*
142  * @ingroup sys_mutex
143  * Create a new mutex.
144  * Note that mutexes are expected to not be taken recursively by the lwIP code,
145  * so both implementation types (recursive or non-recursive) should work.
146  * @param mutex pointer to the mutex to create
147  * @return ERR_OK if successful, another err_t otherwise
148  */
149 err_t sys_mutex_new(sys_mutex_t *mutex);
150 /*
151  * @ingroup sys_mutex
152  * Lock a mutex
153  * @param mutex the mutex to lock
154  */
155 void sys_mutex_lock(sys_mutex_t *mutex);
156 /*
157  * @ingroup sys_mutex
158  * Unlock a mutex
159  * @param mutex the mutex to unlock
160  */
161 void sys_mutex_unlock(sys_mutex_t *mutex);
162 /*
163  * @ingroup sys_mutex
164  * Delete a semaphore
165  * @param mutex the mutex to delete
166  */
167 void sys_mutex_free(sys_mutex_t *mutex);
168 #ifndef sys_mutex_valid
169 /*
170  * @ingroup sys_mutex
171  * Check if a mutex is valid/allocated: return 1 for valid, 0 for invalid
172  */
173 int sys_mutex_valid(sys_mutex_t *mutex);
174 #endif
175 #ifndef sys_mutex_set_invalid
176 /*
177  * @ingroup sys_mutex
178  * Set a mutex invalid so that sys_mutex_valid returns 0
179  */
180 void sys_mutex_set_invalid(sys_mutex_t *mutex);
181 #endif
182 #endif /* LWIP_COMPAT_MUTEX */
183 
184 /* Semaphore functions: */
185 
186 /*
187  * @ingroup sys_sem
188  * Create a new semaphore
189  * @param sem pointer to the semaphore to create
190  * @param count initial count of the semaphore
191  * @return ERR_OK if successful, another err_t otherwise
192  */
193 err_t sys_sem_new(sys_sem_t *sem, u8_t count);
194 /*
195  * @ingroup sys_sem
196  * Signals a semaphore
197  * @param sem the semaphore to signal
198  */
199 void sys_sem_signal(sys_sem_t *sem);
200 /*
201  * @ingroup sys_sem
202  * Wait for a semaphore for the specified timeout
203  * @param sem the semaphore to wait for
204  * @param timeout timeout in milliseconds to wait (0 = wait forever)
205  * @return time (in milliseconds) waited for the semaphore
206  *         or SYS_ARCH_TIMEOUT on timeout
207  */
208 u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout);
209 /*
210  * @ingroup sys_sem
211  * Delete a semaphore
212  * @param sem semaphore to delete
213  */
214 void sys_sem_free(sys_sem_t *sem);
215 /* Wait for a semaphore - forever/no timeout */
216 #define sys_sem_wait(sem)                  sys_arch_sem_wait(sem, 0)
217 #ifndef sys_sem_valid
218 /*
219  * @ingroup sys_sem
220  * Check if a semaphore is valid/allocated: return 1 for valid, 0 for invalid
221  */
222 int sys_sem_valid(sys_sem_t *sem);
223 #endif
224 #ifndef sys_sem_set_invalid
225 /*
226  * @ingroup sys_sem
227  * Set a semaphore invalid so that sys_sem_valid returns 0
228  */
229 void sys_sem_set_invalid(sys_sem_t *sem);
230 #endif
231 #ifndef sys_sem_valid_val
232 /*
233  * Same as sys_sem_valid() but taking a value, not a pointer
234  */
235 #define sys_sem_valid_val(sem)       sys_sem_valid(&(sem))
236 #endif
237 #ifndef sys_sem_set_invalid_val
238 /*
239  * Same as sys_sem_set_invalid() but taking a value, not a pointer
240  */
241 #define sys_sem_set_invalid_val(sem) sys_sem_set_invalid(&(sem))
242 #endif
243 
244 #ifndef sys_msleep
245 /*
246  * @ingroup sys_misc
247  * Sleep for specified number of ms
248  */
249 void sys_msleep(u32_t ms); /* only has a (close to) 1 ms resolution. */
250 #endif
251 
252 /* Mailbox functions. */
253 
254 /*
255  * @ingroup sys_mbox
256  * Create a new mbox of specified size
257  * @param mbox pointer to the mbox to create
258  * @param size (minimum) number of messages in this mbox
259  * @return ERR_OK if successful, another err_t otherwise
260  */
261 err_t sys_mbox_new_ext(sys_mbox_t *mbox, int size, unsigned char is_auto_expand);
262 #define sys_mbox_new(_mb, size) sys_mbox_new_ext((_mb), (size), MBOX_NO_EXPAND)
263 #define sys_mbox_new_auto_expand(_mb, size) sys_mbox_new_ext((_mb), (size), MBOX_AUTO_EXPAND)
264 
265 /*
266  * @ingroup sys_mbox
267  * Post a message to an mbox - may not fail
268  * -> blocks if full, only used from tasks not from ISR
269  * @param mbox mbox to posts the message
270  * @param msg message to post (ATTENTION: can be NULL)
271  */
272 void sys_mbox_post(sys_mbox_t *mbox, void *msg);
273 #ifdef DUAL_MBOX
274 err_t sys_dual_mbox_new(sys_dual_mbox_t *dmbox, int size);
275 void sys_dual_mbox_post(sys_dual_mbox_t *dmbox, void *msg);
276 void sys_dual_mbox_post_priority(sys_dual_mbox_t *dmbox, void *msg);
277 #endif /* DUAL_MBOX */
278 
279 /*
280  * @ingroup sys_mbox
281  * Try to post a message to an mbox - may fail if full or ISR
282  * @param mbox mbox to posts the message
283  * @param msg message to post (ATTENTION: can be NULL)
284  */
285 err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg);
286 #ifdef DUAL_MBOX
287 err_t sys_dual_mbox_trypost(sys_dual_mbox_t *dmbox, void *msg);
288 #endif /* DUAL_MBOX */
289 
290 u32_t sys_arch_mbox_fetch_ext(sys_mbox_t *mbox, void **msg, u32_t timeout, u8_t ignore_timeout);
291 #ifdef DUAL_MBOX
292 u32_t sys_arch_dual_mbox_fetch_ext(sys_dual_mbox_t *dmbox, void **msg, u32_t timeout, u8_t ignore_timeout);
293 #endif /* DUAL_MBOX */
294 
295 /* Wait for a new message to arrive in the mbox
296  * @param mbox mbox to get a message from
297  * @param msg pointer where the message is stored
298  * @param timeout maximum time (in milliseconds) to wait for a message (0 = wait forever)
299  * @return time (in milliseconds) waited for a message, may be 0 if not waited
300            or SYS_ARCH_TIMEOUT on timeout
301  *         The returned time has to be accurate to prevent timer jitter!
302  */
303 u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout);
304 #ifdef DUAL_MBOX
305 u32_t sys_arch_dual_mbox_fetch(sys_dual_mbox_t *dmbox, void **msg, u32_t timeout);
306 #endif /* DUAL_MBOX */
307 
308 /* Allow port to override with a macro, e.g. special timout for sys_arch_mbox_fetch() */
309 #define sys_arch_mbox_tryfetch(mbox, msg) sys_arch_mbox_fetch_ext(mbox, msg, 1, 1)
310 #ifdef DUAL_MBOX
311 #define sys_arch_dual_mbox_tryfetch(dmbox, msg) sys_arch_dual_mbox_fetch_ext(dmbox, msg, 1, 1)
312 #endif /* DUAL_MBOX */
313 
314 /* For now, we map straight to sys_arch implementation. */
315 #define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg)
316 #ifdef DUAL_MBOX
317 #define sys_dual_mbox_tryfetch(dmbox, msg) sys_arch_dual_mbox_tryfetch(dmbox, msg)
318 #endif /* DUAL_MBOX */
319 /*
320  * @ingroup sys_mbox
321  * Delete an mbox
322  * @param mbox mbox to delete
323  */
324 void sys_mbox_free(sys_mbox_t *mbox);
325 #ifdef DUAL_MBOX
326 void sys_dual_mbox_free(sys_dual_mbox_t *dmbox);
327 #endif /* DUAL_MBOX */
328 
329 #define sys_mbox_fetch(mbox, msg) sys_arch_mbox_fetch(mbox, msg, 0)
330 #ifdef DUAL_MBOX
331 #define sys_dual_mbox_fetch(dmbox, msg) sys_arch_dual_mbox_fetch(dmbox, msg, 0)
332 #endif /* DUAL_MBOX */
333 
334 #ifndef sys_mbox_valid
335 /*
336  * @ingroup sys_mbox
337  * Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid
338  */
339 int sys_mbox_valid(sys_mbox_t *mbox);
340 #endif
341 #ifndef sys_mbox_set_invalid
342 /*
343  * @ingroup sys_mbox
344  * Set an mbox invalid so that sys_mbox_valid returns 0
345  */
346 void sys_mbox_set_invalid(sys_mbox_t *mbox);
347 #endif
348 
349 #ifndef sys_dual_mbox_valid
350 /* Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid */
351 int sys_dual_mbox_valid(sys_dual_mbox_t *dmbox);
352 #endif
353 #ifndef sys_dual_mbox_set_invalid
354 /* Set an mbox invalid so that sys_mbox_valid returns 0 */
355 void sys_dual_mbox_set_invalid(sys_dual_mbox_t *dmbox);
356 #endif
357 
358 #ifndef sys_mbox_valid_val
359 /*
360  * Same as sys_mbox_valid() but taking a value, not a pointer
361  */
362 #define sys_mbox_valid_val(mbox)       sys_mbox_valid(&(mbox))
363 #endif
364 #ifndef sys_mbox_set_invalid_val
365 /*
366  * Same as sys_mbox_set_invalid() but taking a value, not a pointer
367  */
368 #define sys_mbox_set_invalid_val(mbox) sys_mbox_set_invalid(&(mbox))
369 #endif
370 
371 /*
372  * @ingroup sys_misc
373  * The only thread function:
374  * Creates a new thread
375  * ATTENTION: although this function returns a value, it MUST NOT FAIL (ports have to assert this!)
376  * @param name human-readable name for the thread (used for debugging purposes)
377  * @param thread thread-function
378  * @param arg parameter passed to 'thread'
379  * @param stacksize stack size in bytes for the new thread (may be ignored by ports)
380  * @param prio priority of the new thread (may be ignored by ports) */
381 sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio);
382 
383 #endif /* NO_SYS */
384 
385 /* sys_init() must be called before anything else. */
386 void sys_init(void);
387 
388 #ifndef sys_jiffies
389 /*
390  * Ticks/jiffies since power up.
391  */
392 u32_t sys_jiffies(void);
393 #endif
394 
395 /*
396  * @ingroup sys_time
397  * Returns the current time in milliseconds,
398  * may be the same as sys_jiffies or at least based on it.
399  */
400 u32_t sys_now(void);
401 
402 /* Critical Region Protection */
403 /* These functions must be implemented in the sys_arch.c file.
404    In some implementations they can provide a more light-weight protection
405    mechanism than using semaphores. Otherwise semaphores can be used for
406    implementation */
407 #ifndef SYS_ARCH_PROTECT
408 /* SYS_LIGHTWEIGHT_PROT
409  * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection
410  * for certain critical regions during buffer allocation, deallocation and memory
411  * allocation and deallocation.
412  */
413 #if SYS_LIGHTWEIGHT_PROT
414 
415 /*
416  * @ingroup sys_prot
417  * SYS_ARCH_DECL_PROTECT
418  * declare a protection variable. This macro will default to defining a variable of
419  * type sys_prot_t. If a particular port needs a different implementation, then
420  * this macro may be defined in sys_arch.h.
421  */
422 #define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev
423 /*
424  * @ingroup sys_prot
425  * SYS_ARCH_PROTECT
426  * Perform a "fast" protect. This could be implemented by
427  * disabling interrupts for an embedded system or by using a semaphore or
428  * mutex. The implementation should allow calling SYS_ARCH_PROTECT when
429  * already protected. The old protection level is returned in the variable
430  * "lev". This macro will default to calling the sys_arch_protect() function
431  * which should be implemented in sys_arch.c. If a particular port needs a
432  * different implementation, then this macro may be defined in sys_arch.h
433  */
434 #define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect()
435 /*
436  * @ingroup sys_prot
437  * SYS_ARCH_UNPROTECT
438  * Perform a "fast" set of the protection level to "lev". This could be
439  * implemented by setting the interrupt level to "lev" within the MACRO or by
440  * using a semaphore or mutex.  This macro will default to calling the
441  * sys_arch_unprotect() function which should be implemented in
442  * sys_arch.c. If a particular port needs a different implementation, then
443  * this macro may be defined in sys_arch.h
444  */
445 #define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev)
446 sys_prot_t sys_arch_protect(void);
447 void sys_arch_unprotect(sys_prot_t pval);
448 
449 #else
450 
451 #define SYS_ARCH_DECL_PROTECT(lev)
452 #define SYS_ARCH_PROTECT(lev)
453 #define SYS_ARCH_UNPROTECT(lev)
454 
455 #endif /* SYS_LIGHTWEIGHT_PROT */
456 
457 #endif /* SYS_ARCH_PROTECT */
458 
459 /*
460  * Macros to set/get and increase/decrease variables in a thread-safe way.
461  * Use these for accessing variable that are used from more than one thread.
462  */
463 
464 #ifndef SYS_ARCH_INC
465 #define SYS_ARCH_INC(var, val) do { \
466                                 SYS_ARCH_DECL_PROTECT(old_level); \
467                                 SYS_ARCH_PROTECT(old_level); \
468                                 var += val; \
469                                 SYS_ARCH_UNPROTECT(old_level); \
470                               } while (0)
471 #endif /* SYS_ARCH_INC */
472 
473 #ifndef SYS_ARCH_DEC
474 #define SYS_ARCH_DEC(var, val) do { \
475                                 SYS_ARCH_DECL_PROTECT(old_level); \
476                                 SYS_ARCH_PROTECT(old_level); \
477                                 var -= val; \
478                                 SYS_ARCH_UNPROTECT(old_level); \
479                               } while (0)
480 #endif /* SYS_ARCH_DEC */
481 
482 #ifndef SYS_ARCH_GET
483 #define SYS_ARCH_GET(var, ret) do { \
484                                 SYS_ARCH_DECL_PROTECT(old_level); \
485                                 SYS_ARCH_PROTECT(old_level); \
486                                 ret = var; \
487                                 SYS_ARCH_UNPROTECT(old_level); \
488                               } while (0)
489 #endif /* SYS_ARCH_GET */
490 
491 #ifndef SYS_ARCH_SET
492 #define SYS_ARCH_SET(var, val) do { \
493                                 SYS_ARCH_DECL_PROTECT(old_level); \
494                                 SYS_ARCH_PROTECT(old_level); \
495                                 var = val; \
496                                 SYS_ARCH_UNPROTECT(old_level); \
497                               } while (0)
498 #endif /* SYS_ARCH_SET */
499 
500 #ifndef SYS_ARCH_LOCKED
501 #define SYS_ARCH_LOCKED(code) do { \
502                                 SYS_ARCH_DECL_PROTECT(old_level); \
503                                 SYS_ARCH_PROTECT(old_level); \
504                                 code; \
505                                 SYS_ARCH_UNPROTECT(old_level); \
506                               } while (0)
507 #endif /* SYS_ARCH_LOCKED */
508 
509 #if defined (__cplusplus) && __cplusplus
510 }
511 #endif
512 
513 #endif /* LWIP_HDR_SYS_H */
514