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