BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | sys_arch interface for lwIP |
2 | |||
3 | Author: Adam Dunkels |
||
4 | Simon Goldschmidt |
||
5 | |||
6 | The operating system emulation layer provides a common interface |
||
7 | between the lwIP code and the underlying operating system kernel. The |
||
8 | general idea is that porting lwIP to new architectures requires only |
||
9 | small changes to a few header files and a new sys_arch |
||
10 | implementation. It is also possible to do a sys_arch implementation |
||
11 | that does not rely on any underlying operating system. |
||
12 | |||
13 | The sys_arch provides semaphores, mailboxes and mutexes to lwIP. For the full |
||
14 | lwIP functionality, multiple threads support can be implemented in the |
||
15 | sys_arch, but this is not required for the basic lwIP |
||
16 | functionality. Timer scheduling is implemented in lwIP, but can be implemented |
||
17 | by the sys_arch port (LWIP_TIMERS_CUSTOM==1). |
||
18 | |||
19 | In addition to the source file providing the functionality of sys_arch, |
||
20 | the OS emulation layer must provide several header files defining |
||
21 | macros used throughout lwip. The files required and the macros they |
||
22 | must define are listed below the sys_arch description. |
||
23 | |||
24 | Semaphores can be either counting or binary - lwIP works with both |
||
25 | kinds. Mailboxes should be implemented as a queue which allows multiple messages |
||
26 | to be posted (implementing as a rendez-vous point where only one message can be |
||
27 | posted at a time can have a highly negative impact on performance). A message |
||
28 | in a mailbox is just a pointer, nothing more. |
||
29 | |||
30 | Semaphores are represented by the type "sys_sem_t" which is typedef'd |
||
31 | in the sys_arch.h file. Mailboxes are equivalently represented by the |
||
32 | type "sys_mbox_t". Mutexes are represented by the type "sys_mutex_t". |
||
33 | lwIP does not place any restrictions on how these types are represented |
||
34 | internally. |
||
35 | |||
36 | Since lwIP 1.4.0, semaphore, mutexes and mailbox functions are prototyped in a way that |
||
37 | allows both using pointers or actual OS structures to be used. This way, memory |
||
38 | required for such types can be either allocated in place (globally or on the |
||
39 | stack) or on the heap (allocated internally in the "*_new()" functions). |
||
40 | |||
41 | The following functions must be implemented by the sys_arch: |
||
42 | |||
43 | - void sys_init(void) |
||
44 | |||
45 | Is called to initialize the sys_arch layer. |
||
46 | |||
47 | - err_t sys_sem_new(sys_sem_t *sem, u8_t count) |
||
48 | |||
49 | Creates a new semaphore. The semaphore is allocated to the memory that 'sem' |
||
50 | points to (which can be both a pointer or the actual OS structure). |
||
51 | The "count" argument specifies the initial state of the semaphore (which is |
||
52 | either 0 or 1). |
||
53 | If the semaphore has been created, ERR_OK should be returned. Returning any |
||
54 | other error will provide a hint what went wrong, but except for assertions, |
||
55 | no real error handling is implemented. |
||
56 | |||
57 | - void sys_sem_free(sys_sem_t *sem) |
||
58 | |||
59 | Deallocates a semaphore. |
||
60 | |||
61 | - void sys_sem_signal(sys_sem_t *sem) |
||
62 | |||
63 | Signals a semaphore. |
||
64 | |||
65 | - u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) |
||
66 | |||
67 | Blocks the thread while waiting for the semaphore to be signaled. If the |
||
68 | "timeout" argument is non-zero, the thread should only be blocked for the |
||
69 | specified time (measured in milliseconds). If the "timeout" argument is zero, |
||
70 | the thread should be blocked until the semaphore is signalled. |
||
71 | |||
72 | The return value is SYS_ARCH_TIMEOUT if the semaphore wasn't signaled within |
||
73 | the specified time or any other value if it was signaled (with or without |
||
74 | waiting). |
||
75 | |||
76 | Notice that lwIP implements a function with a similar name, |
||
77 | sys_sem_wait(), that uses the sys_arch_sem_wait() function. |
||
78 | |||
79 | - int sys_sem_valid(sys_sem_t *sem) |
||
80 | |||
81 | Returns 1 if the semaphore is valid, 0 if it is not valid. |
||
82 | When using pointers, a simple way is to check the pointer for != NULL. |
||
83 | When directly using OS structures, implementing this may be more complex. |
||
84 | This may also be a define, in which case the function is not prototyped. |
||
85 | |||
86 | - void sys_sem_set_invalid(sys_sem_t *sem) |
||
87 | |||
88 | Invalidate a semaphore so that sys_sem_valid() returns 0. |
||
89 | ATTENTION: This does NOT mean that the semaphore shall be deallocated: |
||
90 | sys_sem_free() is always called before calling this function! |
||
91 | This may also be a define, in which case the function is not prototyped. |
||
92 | |||
93 | - void sys_mutex_new(sys_mutex_t *mutex) |
||
94 | |||
95 | Creates a new mutex. The mutex is allocated to the memory that 'mutex' |
||
96 | points to (which can be both a pointer or the actual OS structure). |
||
97 | If the mutex has been created, ERR_OK should be returned. Returning any |
||
98 | other error will provide a hint what went wrong, but except for assertions, |
||
99 | no real error handling is implemented. |
||
100 | |||
101 | - void sys_mutex_free(sys_mutex_t *mutex) |
||
102 | |||
103 | Deallocates a mutex. |
||
104 | |||
105 | - void sys_mutex_lock(sys_mutex_t *mutex) |
||
106 | |||
107 | Blocks the thread until the mutex can be grabbed. |
||
108 | |||
109 | - void sys_mutex_unlock(sys_mutex_t *mutex) |
||
110 | |||
111 | Releases the mutex previously locked through 'sys_mutex_lock()'. |
||
112 | |||
113 | - void sys_mutex_valid(sys_mutex_t *mutex) |
||
114 | |||
115 | Returns 1 if the mutes is valid, 0 if it is not valid. |
||
116 | When using pointers, a simple way is to check the pointer for != NULL. |
||
117 | When directly using OS structures, implementing this may be more complex. |
||
118 | This may also be a define, in which case the function is not prototyped. |
||
119 | |||
120 | - void sys_mutex_set_invalid(sys_mutex_t *mutex) |
||
121 | |||
122 | Invalidate a mutex so that sys_mutex_valid() returns 0. |
||
123 | ATTENTION: This does NOT mean that the mutex shall be deallocated: |
||
124 | sys_mutex_free() is always called before calling this function! |
||
125 | This may also be a define, in which case the function is not prototyped. |
||
126 | |||
127 | - err_t sys_mbox_new(sys_mbox_t *mbox, int size) |
||
128 | |||
129 | Creates an empty mailbox for maximum "size" elements. Elements stored |
||
130 | in mailboxes are pointers. You have to define macros "_MBOX_SIZE" |
||
131 | in your lwipopts.h, or ignore this parameter in your implementation |
||
132 | and use a default size. |
||
133 | If the mailbox has been created, ERR_OK should be returned. Returning any |
||
134 | other error will provide a hint what went wrong, but except for assertions, |
||
135 | no real error handling is implemented. |
||
136 | |||
137 | - void sys_mbox_free(sys_mbox_t *mbox) |
||
138 | |||
139 | Deallocates a mailbox. If there are messages still present in the |
||
140 | mailbox when the mailbox is deallocated, it is an indication of a |
||
141 | programming error in lwIP and the developer should be notified. |
||
142 | |||
143 | - void sys_mbox_post(sys_mbox_t *mbox, void *msg) |
||
144 | |||
145 | Posts the "msg" to the mailbox. This function have to block until |
||
146 | the "msg" is really posted. |
||
147 | |||
148 | - err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg) |
||
149 | |||
150 | Try to post the "msg" to the mailbox. Returns ERR_MEM if this one |
||
151 | is full, else, ERR_OK if the "msg" is posted. |
||
152 | |||
153 | - u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) |
||
154 | |||
155 | Blocks the thread until a message arrives in the mailbox, but does |
||
156 | not block the thread longer than "timeout" milliseconds (similar to |
||
157 | the sys_arch_sem_wait() function). If "timeout" is 0, the thread should |
||
158 | be blocked until a message arrives. The "msg" argument is a result |
||
159 | parameter that is set by the function (i.e., by doing "*msg = |
||
160 | ptr"). The "msg" parameter maybe NULL to indicate that the message |
||
161 | should be dropped. |
||
162 | |||
163 | The return values are the same as for the sys_arch_sem_wait() function: |
||
164 | SYS_ARCH_TIMEOUT if there was a timeout, any other value if a messages |
||
165 | is received. |
||
166 | |||
167 | Note that a function with a similar name, sys_mbox_fetch(), is |
||
168 | implemented by lwIP. |
||
169 | |||
170 | - u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) |
||
171 | |||
172 | This is similar to sys_arch_mbox_fetch, however if a message is not |
||
173 | present in the mailbox, it immediately returns with the code |
||
174 | SYS_MBOX_EMPTY. On success 0 is returned. |
||
175 | |||
176 | To allow for efficient implementations, this can be defined as a |
||
177 | function-like macro in sys_arch.h instead of a normal function. For |
||
178 | example, a naive implementation could be: |
||
179 | #define sys_arch_mbox_tryfetch(mbox,msg) \ |
||
180 | sys_arch_mbox_fetch(mbox,msg,1) |
||
181 | although this would introduce unnecessary delays. |
||
182 | |||
183 | - int sys_mbox_valid(sys_mbox_t *mbox) |
||
184 | |||
185 | Returns 1 if the mailbox is valid, 0 if it is not valid. |
||
186 | When using pointers, a simple way is to check the pointer for != NULL. |
||
187 | When directly using OS structures, implementing this may be more complex. |
||
188 | This may also be a define, in which case the function is not prototyped. |
||
189 | |||
190 | - void sys_mbox_set_invalid(sys_mbox_t *mbox) |
||
191 | |||
192 | Invalidate a mailbox so that sys_mbox_valid() returns 0. |
||
193 | ATTENTION: This does NOT mean that the mailbox shall be deallocated: |
||
194 | sys_mbox_free() is always called before calling this function! |
||
195 | This may also be a define, in which case the function is not prototyped. |
||
196 | |||
197 | If threads are supported by the underlying operating system and if |
||
198 | such functionality is needed in lwIP, the following function will have |
||
199 | to be implemented as well: |
||
200 | |||
201 | - sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio) |
||
202 | |||
203 | Starts a new thread named "name" with priority "prio" that will begin its |
||
204 | execution in the function "thread()". The "arg" argument will be passed as an |
||
205 | argument to the thread() function. The stack size to used for this thread is |
||
206 | the "stacksize" parameter. The id of the new thread is returned. Both the id |
||
207 | and the priority are system dependent. |
||
208 | |||
209 | When lwIP is used from more than one context (e.g. from multiple threads OR from |
||
210 | main-loop and from interrupts), the SYS_LIGHTWEIGHT_PROT protection SHOULD be enabled! |
||
211 | |||
212 | - sys_prot_t sys_arch_protect(void) |
||
213 | |||
214 | This optional function does a "fast" critical region protection. This function |
||
215 | is only called during very short critical regions. An embedded system which |
||
216 | supports ISR-based drivers might want to implement this function by disabling |
||
217 | interrupts. Task-based systems might want to implement this by using a mutex |
||
218 | or disabling tasking. This function should support recursive calls from the |
||
219 | same task or interrupt. In other words, sys_arch_protect() could be called |
||
220 | while already protected. |
||
221 | |||
222 | The return value is opaque to lwip and passed to the sys_arch_unprotect() call |
||
223 | matching the sys_arch_protect() call at the same nesting level. This value |
||
224 | might be used to restore the status. However implementations may depend on |
||
225 | every call to sys_arch_protect() having a matching call to sys_arch_unprotect() |
||
226 | and thus can use a nesting count or a recursive mutex. |
||
227 | |||
228 | sys_arch_protect() is only required if your port is supporting an operating |
||
229 | system. |
||
230 | |||
231 | - void sys_arch_unprotect(sys_prot_t pval) |
||
232 | |||
233 | This optional function does a "fast" exit of critical region protection |
||
234 | nesting level. The value passed in pval is the opaque value returned the |
||
235 | respective call to sys_arch_protect(). See the documentation for |
||
236 | sys_arch_protect() for more information. This function is only required if |
||
237 | your port is supporting an operating system. |
||
238 | |||
239 | For some configurations, you also need: |
||
240 | |||
241 | - u32_t sys_now(void) |
||
242 | |||
243 | This optional function returns the current time in milliseconds (don't care |
||
244 | for wraparound, this is only used for time diffs). |
||
245 | Not implementing this function means you cannot use some modules (e.g. TCP |
||
246 | timestamps, internal timeouts for NO_SYS==1). |
||
247 | |||
248 | |||
249 | Note: |
||
250 | |||
251 | Be careful with using mem_malloc() in sys_arch. When malloc() refers to |
||
252 | mem_malloc() you can run into a circular function call problem. In mem.c |
||
253 | mem_init() tries to allcate a semaphore using mem_malloc, which of course |
||
254 | can't be performed when sys_arch uses mem_malloc. |
||
255 | |||
256 | ------------------------------------------------------------------------------- |
||
257 | Additional files required for the "OS support" emulation layer: |
||
258 | ------------------------------------------------------------------------------- |
||
259 | |||
260 | cc.h - Architecture environment, some compiler specific, some |
||
261 | environment specific (probably should move env stuff |
||
262 | to sys_arch.h.) |
||
263 | |||
264 | Typedefs for the types used by lwip - |
||
265 | u8_t, s8_t, u16_t, s16_t, u32_t, s32_t, mem_ptr_t |
||
266 | |||
267 | Compiler hints for packing lwip's structures - |
||
268 | PACK_STRUCT_FIELD(x) |
||
269 | PACK_STRUCT_STRUCT |
||
270 | PACK_STRUCT_BEGIN |
||
271 | PACK_STRUCT_END |
||
272 | |||
273 | Platform specific diagnostic output - |
||
274 | LWIP_PLATFORM_DIAG(x) - non-fatal, print a message. |
||
275 | LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution. |
||
276 | Portability defines for printf formatters: |
||
277 | U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F |
||
278 | |||
279 | "lightweight" synchronization mechanisms - |
||
280 | SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable. |
||
281 | SYS_ARCH_PROTECT(x) - enter protection mode. |
||
282 | SYS_ARCH_UNPROTECT(x) - leave protection mode. |
||
283 | |||
284 | If the compiler does not provide memset() this file must include a |
||
285 | definition of it, or include a file which defines it. |
||
286 | |||
287 | This file must either include a system-local <errno.h> which defines |
||
288 | the standard *nix error codes (or define LWIP_ERRNO_INCLUDE to that file name), |
||
289 | or it should #define LWIP_PROVIDE_ERRNO to make lwip/arch.h define the codes |
||
290 | which are used throughout. |
||
291 | |||
292 | |||
293 | perf.h - Architecture specific performance measurement. |
||
294 | Measurement calls made throughout lwip, these can be defined to nothing. |
||
295 | PERF_START - start measuring something. |
||
296 | PERF_STOP(x) - stop measuring something, and record the result. |
||
297 | |||
298 | sys_arch.h - Tied to sys_arch.c |
||
299 | |||
300 | Arch dependent types for the following objects: |
||
301 | sys_sem_t, sys_mbox_t, sys_thread_t, |
||
302 | And, optionally: |
||
303 | sys_prot_t |
||
304 | |||
305 | Defines to set vars of sys_mbox_t and sys_sem_t to NULL. |
||
306 | SYS_MBOX_NULL NULL |
||
307 | SYS_SEM_NULL NULL |