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