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 /** 38 * @defgroup sys_layer System abstraction layer 39 * @ingroup infrastructure 40 * @verbinclude "sys_arch.txt" 41 * 42 * @defgroup sys_os OS abstraction layer 43 * @ingroup sys_layer 44 * No need to implement functions in this section in NO_SYS mode. 45 * 46 * @defgroup sys_sem Semaphores 47 * @ingroup sys_os 48 * 49 * @defgroup sys_mutex Mutexes 50 * @ingroup sys_os 51 * Mutexes are recommended to correctly handle priority inversion, 52 * especially if you use LWIP_CORE_LOCKING . 53 * 54 * @defgroup sys_mbox Mailboxes 55 * @ingroup sys_os 56 * 57 * @defgroup sys_time Time 58 * @ingroup sys_layer 59 * 60 * @defgroup sys_prot Critical sections 61 * @ingroup sys_layer 62 * Used to protect short regions of code against concurrent access. 63 * - Your system is a bare-metal system (probably with an RTOS) 64 * and interrupts are under your control: 65 * Implement this as LockInterrupts() / UnlockInterrupts() 66 * - Your system uses an RTOS with deferred interrupt handling from a 67 * worker thread: Implement as a global mutex or lock/unlock scheduler 68 * - Your system uses a high-level OS with e.g. POSIX signals: 69 * Implement as a global mutex 70 * 71 * @defgroup sys_misc Misc 72 * @ingroup sys_os 73 */ 74 75 #ifndef LWIP_HDR_SYS_H 76 #define LWIP_HDR_SYS_H 77 78 #include "lwip/opt.h" 79 80 #ifdef __cplusplus 81 extern "C" { 82 #endif 83 84 #if NO_SYS 85 86 /* For a totally minimal and standalone system, we provide null 87 definitions of the sys_ functions. */ 88 typedef u8_t sys_sem_t; 89 typedef u8_t sys_mutex_t; 90 typedef u8_t sys_mbox_t; 91 92 #define sys_sem_new(s, c) ERR_OK 93 #define sys_sem_signal(s) 94 #define sys_sem_wait(s) 95 #define sys_arch_sem_wait(s,t) 96 #define sys_sem_free(s) 97 #define sys_sem_valid(s) 0 98 #define sys_sem_valid_val(s) 0 99 #define sys_sem_set_invalid(s) 100 #define sys_sem_set_invalid_val(s) 101 #define sys_mutex_new(mu) ERR_OK 102 #define sys_mutex_lock(mu) 103 #define sys_mutex_unlock(mu) 104 #define sys_mutex_free(mu) 105 #define sys_mutex_valid(mu) 0 106 #define sys_mutex_set_invalid(mu) 107 #define sys_mbox_new(m, s) ERR_OK 108 #define sys_mbox_fetch(m,d) 109 #define sys_mbox_tryfetch(m,d) 110 #define sys_mbox_post(m,d) 111 #define sys_mbox_trypost(m,d) 112 #define sys_mbox_free(m) 113 #define sys_mbox_valid(m) 114 #define sys_mbox_valid_val(m) 115 #define sys_mbox_set_invalid(m) 116 #define sys_mbox_set_invalid_val(m) 117 118 #define sys_thread_new(n,t,a,s,p) 119 120 #define sys_msleep(t) 121 122 #else /* NO_SYS */ 123 124 /** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */ 125 #define SYS_ARCH_TIMEOUT 0xffffffffUL 126 127 /** sys_mbox_tryfetch() returns SYS_MBOX_EMPTY if appropriate. 128 * For now we use the same magic value, but we allow this to change in future. 129 */ 130 #define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT 131 132 #include "lwip/err.h" 133 #include "arch/sys_arch.h" 134 135 /** Function prototype for thread functions */ 136 typedef void (*lwip_thread_fn)(void *arg); 137 138 /* Function prototypes for functions to be implemented by platform ports 139 (in sys_arch.c) */ 140 141 /* Mutex functions: */ 142 143 /** Define LWIP_COMPAT_MUTEX if the port has no mutexes and binary semaphores 144 should be used instead */ 145 #ifndef LWIP_COMPAT_MUTEX 146 #define LWIP_COMPAT_MUTEX 0 147 #endif 148 149 #if LWIP_COMPAT_MUTEX 150 /* for old ports that don't have mutexes: define them to binary semaphores */ 151 #define sys_mutex_t sys_sem_t 152 #define sys_mutex_new(mutex) sys_sem_new(mutex, 1) 153 #define sys_mutex_lock(mutex) sys_sem_wait(mutex) 154 #define sys_mutex_unlock(mutex) sys_sem_signal(mutex) 155 #define sys_mutex_free(mutex) sys_sem_free(mutex) 156 #define sys_mutex_valid(mutex) sys_sem_valid(mutex) 157 #define sys_mutex_set_invalid(mutex) sys_sem_set_invalid(mutex) 158 159 #else /* LWIP_COMPAT_MUTEX */ 160 161 /** 162 * @ingroup sys_mutex 163 * Create a new mutex. 164 * Note that mutexes are expected to not be taken recursively by the lwIP code, 165 * so both implementation types (recursive or non-recursive) should work. 166 * @param mutex pointer to the mutex to create 167 * @return ERR_OK if successful, another err_t otherwise 168 */ 169 err_t sys_mutex_new(sys_mutex_t *mutex); 170 /** 171 * @ingroup sys_mutex 172 * Lock a mutex 173 * @param mutex the mutex to lock 174 */ 175 void sys_mutex_lock(sys_mutex_t *mutex); 176 /** 177 * @ingroup sys_mutex 178 * Unlock a mutex 179 * @param mutex the mutex to unlock 180 */ 181 void sys_mutex_unlock(sys_mutex_t *mutex); 182 /** 183 * @ingroup sys_mutex 184 * Delete a semaphore 185 * @param mutex the mutex to delete 186 */ 187 void sys_mutex_free(sys_mutex_t *mutex); 188 #ifndef sys_mutex_valid 189 /** 190 * @ingroup sys_mutex 191 * Check if a mutex is valid/allocated: return 1 for valid, 0 for invalid 192 */ 193 int sys_mutex_valid(sys_mutex_t *mutex); 194 #endif 195 #ifndef sys_mutex_set_invalid 196 /** 197 * @ingroup sys_mutex 198 * Set a mutex invalid so that sys_mutex_valid returns 0 199 */ 200 void sys_mutex_set_invalid(sys_mutex_t *mutex); 201 #endif 202 #endif /* LWIP_COMPAT_MUTEX */ 203 204 /* Semaphore functions: */ 205 206 /** 207 * @ingroup sys_sem 208 * Create a new semaphore 209 * @param sem pointer to the semaphore to create 210 * @param count initial count of the semaphore 211 * @return ERR_OK if successful, another err_t otherwise 212 */ 213 err_t sys_sem_new(sys_sem_t *sem, u8_t count); 214 /** 215 * @ingroup sys_sem 216 * Signals a semaphore 217 * @param sem the semaphore to signal 218 */ 219 void sys_sem_signal(sys_sem_t *sem); 220 /** 221 * @ingroup sys_sem 222 * Wait for a semaphore for the specified timeout 223 * @param sem the semaphore to wait for 224 * @param timeout timeout in milliseconds to wait (0 = wait forever) 225 * @return time (in milliseconds) waited for the semaphore 226 * or SYS_ARCH_TIMEOUT on timeout 227 */ 228 u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout); 229 /** 230 * @ingroup sys_sem 231 * Delete a semaphore 232 * @param sem semaphore to delete 233 */ 234 void sys_sem_free(sys_sem_t *sem); 235 /** Wait for a semaphore - forever/no timeout */ 236 #define sys_sem_wait(sem) sys_arch_sem_wait(sem, 0) 237 #ifndef sys_sem_valid 238 /** 239 * @ingroup sys_sem 240 * Check if a semaphore is valid/allocated: return 1 for valid, 0 for invalid 241 */ 242 int sys_sem_valid(sys_sem_t *sem); 243 #endif 244 #ifndef sys_sem_set_invalid 245 /** 246 * @ingroup sys_sem 247 * Set a semaphore invalid so that sys_sem_valid returns 0 248 */ 249 void sys_sem_set_invalid(sys_sem_t *sem); 250 #endif 251 #ifndef sys_sem_valid_val 252 /** 253 * Same as sys_sem_valid() but taking a value, not a pointer 254 */ 255 #define sys_sem_valid_val(sem) sys_sem_valid(&(sem)) 256 #endif 257 #ifndef sys_sem_set_invalid_val 258 /** 259 * Same as sys_sem_set_invalid() but taking a value, not a pointer 260 */ 261 #define sys_sem_set_invalid_val(sem) sys_sem_set_invalid(&(sem)) 262 #endif 263 264 #ifndef sys_msleep 265 /** 266 * @ingroup sys_misc 267 * Sleep for specified number of ms 268 */ 269 void sys_msleep(u32_t ms); /* only has a (close to) 1 ms resolution. */ 270 #endif 271 272 /* Mailbox functions. */ 273 274 /** 275 * @ingroup sys_mbox 276 * Create a new mbox of specified size 277 * @param mbox pointer to the mbox to create 278 * @param size (minimum) number of messages in this mbox 279 * @return ERR_OK if successful, another err_t otherwise 280 */ 281 err_t sys_mbox_new(sys_mbox_t *mbox, int size); 282 /** 283 * @ingroup sys_mbox 284 * Post a message to an mbox - may not fail 285 * -> blocks if full, only used from tasks not from ISR 286 * @param mbox mbox to posts the message 287 * @param msg message to post (ATTENTION: can be NULL) 288 */ 289 void sys_mbox_post(sys_mbox_t *mbox, void *msg); 290 /** 291 * @ingroup sys_mbox 292 * Try to post a message to an mbox - may fail if full or ISR 293 * @param mbox mbox to posts the message 294 * @param msg message to post (ATTENTION: can be NULL) 295 */ 296 err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg); 297 /** 298 * @ingroup sys_mbox 299 * Wait for a new message to arrive in the mbox 300 * @param mbox mbox to get a message from 301 * @param msg pointer where the message is stored 302 * @param timeout maximum time (in milliseconds) to wait for a message (0 = wait forever) 303 * @return time (in milliseconds) waited for a message, may be 0 if not waited 304 or SYS_ARCH_TIMEOUT on timeout 305 * The returned time has to be accurate to prevent timer jitter! 306 */ 307 u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout); 308 /* Allow port to override with a macro, e.g. special timeout for sys_arch_mbox_fetch() */ 309 #ifndef sys_arch_mbox_tryfetch 310 /** 311 * @ingroup sys_mbox 312 * Wait for a new message to arrive in the mbox 313 * @param mbox mbox to get a message from 314 * @param msg pointer where the message is stored 315 * @return 0 (milliseconds) if a message has been received 316 * or SYS_MBOX_EMPTY if the mailbox is empty 317 */ 318 u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg); 319 #endif 320 /** 321 * For now, we map straight to sys_arch implementation. 322 */ 323 #define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg) 324 /** 325 * @ingroup sys_mbox 326 * Delete an mbox 327 * @param mbox mbox to delete 328 */ 329 void sys_mbox_free(sys_mbox_t *mbox); 330 #define sys_mbox_fetch(mbox, msg) sys_arch_mbox_fetch(mbox, msg, 0) 331 #ifndef sys_mbox_valid 332 /** 333 * @ingroup sys_mbox 334 * Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid 335 */ 336 int sys_mbox_valid(sys_mbox_t *mbox); 337 #endif 338 #ifndef sys_mbox_set_invalid 339 /** 340 * @ingroup sys_mbox 341 * Set an mbox invalid so that sys_mbox_valid returns 0 342 */ 343 void sys_mbox_set_invalid(sys_mbox_t *mbox); 344 #endif 345 #ifndef sys_mbox_valid_val 346 /** 347 * Same as sys_mbox_valid() but taking a value, not a pointer 348 */ 349 #define sys_mbox_valid_val(mbox) sys_mbox_valid(&(mbox)) 350 #endif 351 #ifndef sys_mbox_set_invalid_val 352 /** 353 * Same as sys_mbox_set_invalid() but taking a value, not a pointer 354 */ 355 #define sys_mbox_set_invalid_val(mbox) sys_mbox_set_invalid(&(mbox)) 356 #endif 357 358 359 /** 360 * @ingroup sys_misc 361 * The only thread function: 362 * Creates a new thread 363 * ATTENTION: although this function returns a value, it MUST NOT FAIL (ports have to assert this!) 364 * @param name human-readable name for the thread (used for debugging purposes) 365 * @param thread thread-function 366 * @param arg parameter passed to 'thread' 367 * @param stacksize stack size in bytes for the new thread (may be ignored by ports) 368 * @param prio priority of the new thread (may be ignored by ports) */ 369 sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio); 370 371 #endif /* NO_SYS */ 372 373 /* sys_init() must be called before anything else. */ 374 void sys_init(void); 375 376 #ifndef sys_jiffies 377 /** 378 * Ticks/jiffies since power up. 379 */ 380 u32_t sys_jiffies(void); 381 #endif 382 383 /** 384 * @ingroup sys_time 385 * Returns the current time in milliseconds, 386 * may be the same as sys_jiffies or at least based on it. 387 */ 388 u32_t sys_now(void); 389 390 /* Critical Region Protection */ 391 /* These functions must be implemented in the sys_arch.c file. 392 In some implementations they can provide a more light-weight protection 393 mechanism than using semaphores. Otherwise semaphores can be used for 394 implementation */ 395 #ifndef SYS_ARCH_PROTECT 396 /** SYS_LIGHTWEIGHT_PROT 397 * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection 398 * for certain critical regions during buffer allocation, deallocation and memory 399 * allocation and deallocation. 400 */ 401 #if SYS_LIGHTWEIGHT_PROT 402 403 /** 404 * @ingroup sys_prot 405 * SYS_ARCH_DECL_PROTECT 406 * declare a protection variable. This macro will default to defining a variable of 407 * type sys_prot_t. If a particular port needs a different implementation, then 408 * this macro may be defined in sys_arch.h. 409 */ 410 #define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev 411 /** 412 * @ingroup sys_prot 413 * SYS_ARCH_PROTECT 414 * Perform a "fast" protect. This could be implemented by 415 * disabling interrupts for an embedded system or by using a semaphore or 416 * mutex. The implementation should allow calling SYS_ARCH_PROTECT when 417 * already protected. The old protection level is returned in the variable 418 * "lev". This macro will default to calling the sys_arch_protect() function 419 * which should be implemented in sys_arch.c. If a particular port needs a 420 * different implementation, then this macro may be defined in sys_arch.h 421 */ 422 #define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect() 423 /** 424 * @ingroup sys_prot 425 * SYS_ARCH_UNPROTECT 426 * Perform a "fast" set of the protection level to "lev". This could be 427 * implemented by setting the interrupt level to "lev" within the MACRO or by 428 * using a semaphore or mutex. This macro will default to calling the 429 * sys_arch_unprotect() function which should be implemented in 430 * sys_arch.c. If a particular port needs a different implementation, then 431 * this macro may be defined in sys_arch.h 432 */ 433 #define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev) 434 sys_prot_t sys_arch_protect(void); 435 void sys_arch_unprotect(sys_prot_t pval); 436 437 #define REENTER_DECL_PROTECT(lev) sys_prot_t lev 438 439 sys_prot_t reenter_protect(void); 440 void reenter_unprotect(sys_prot_t pval); 441 442 #define REENTER_PROTECT(lev) lev = reenter_protect() 443 444 #define REENTER_UNPROTECT(lev) reenter_unprotect(lev) 445 446 #else 447 448 #define SYS_ARCH_DECL_PROTECT(lev) 449 #define SYS_ARCH_PROTECT(lev) 450 #define SYS_ARCH_UNPROTECT(lev) 451 452 #endif /* SYS_LIGHTWEIGHT_PROT */ 453 454 #endif /* SYS_ARCH_PROTECT */ 455 456 /* 457 * Macros to set/get and increase/decrease variables in a thread-safe way. 458 * Use these for accessing variable that are used from more than one thread. 459 */ 460 461 #ifndef SYS_ARCH_INC 462 #define SYS_ARCH_INC(var, val) do { \ 463 SYS_ARCH_DECL_PROTECT(old_level); \ 464 SYS_ARCH_PROTECT(old_level); \ 465 var += val; \ 466 SYS_ARCH_UNPROTECT(old_level); \ 467 } while(0) 468 #endif /* SYS_ARCH_INC */ 469 470 #ifndef SYS_ARCH_DEC 471 #define SYS_ARCH_DEC(var, val) do { \ 472 SYS_ARCH_DECL_PROTECT(old_level); \ 473 SYS_ARCH_PROTECT(old_level); \ 474 var -= val; \ 475 SYS_ARCH_UNPROTECT(old_level); \ 476 } while(0) 477 #endif /* SYS_ARCH_DEC */ 478 479 #ifndef SYS_ARCH_GET 480 #define SYS_ARCH_GET(var, ret) do { \ 481 SYS_ARCH_DECL_PROTECT(old_level); \ 482 SYS_ARCH_PROTECT(old_level); \ 483 ret = var; \ 484 SYS_ARCH_UNPROTECT(old_level); \ 485 } while(0) 486 #endif /* SYS_ARCH_GET */ 487 488 #ifndef SYS_ARCH_SET 489 #define SYS_ARCH_SET(var, val) do { \ 490 SYS_ARCH_DECL_PROTECT(old_level); \ 491 SYS_ARCH_PROTECT(old_level); \ 492 var = val; \ 493 SYS_ARCH_UNPROTECT(old_level); \ 494 } while(0) 495 #endif /* SYS_ARCH_SET */ 496 497 498 #ifdef __cplusplus 499 } 500 #endif 501 502 #endif /* LWIP_HDR_SYS_H */ 503