diff --git a/doc/doxygen/lwip.Doxyfile b/doc/doxygen/lwip.Doxyfile index c86326b0..125d3239 100644 --- a/doc/doxygen/lwip.Doxyfile +++ b/doc/doxygen/lwip.Doxyfile @@ -2071,6 +2071,7 @@ INCLUDE_FILE_PATTERNS = *.h PREDEFINED = __DOXYGEN__=1 \ NO_SYS=0 \ SYS_LIGHTWEIGHT_PROT=1 \ + LWIP_TCPIP_CORE_LOCKING=1 \ LWIP_IPV4=1 \ LWIP_IPV6=1 \ LWIP_ICMP=1 \ diff --git a/doc/doxygen/main_page.h b/doc/doxygen/main_page.h index db9c81e4..ad890234 100644 --- a/doc/doxygen/main_page.h +++ b/doc/doxygen/main_page.h @@ -1,4 +1,4 @@ -/** +/** * @defgroup lwip lwIP * * @defgroup infrastructure Infrastructure @@ -7,7 +7,7 @@ * Non thread-safe APIs, callback style for maximum performance and minimum * memory footprint. * - * @defgroup threadsafe_api Thread-safe APIs + * @defgroup sequential_api Sequential-style APIs * Thread-safe APIs, blocking functions. More overhead, but can be called * from any thread except TCPIP thread. * @@ -31,6 +31,63 @@ * @verbinclude "contrib.txt" */ +/** + * @page pitfalls Common pitfalls + * + * Multiple Execution Contexts in lwIP code + * ======================================== + * + * The most common source of lwIP problems is to have multiple execution contexts + * inside the lwIP code. + * + * lwIP can be used in two basic modes: @ref lwip_nosys (no OS/RTOS + * running on target system) or @ref lwip_os (there is an OS running + * on the target system). + * + * Mainloop Mode + * ------------- + * In mainloop mode, only @ref callbackstyle_api can be used. + * The user has two possibilities to ensure there is only one + * exection context at a time in lwIP: + * + * 1) Deliver RX ethernet packets directly in interrupt context to lwIP + * by calling netif->input directly in interrupt. This implies all lwIP + * callback functions are called in IRQ context, which may cause further + * problems in application code: IRQ is blocked for a long time, multiple + * execution contexts in application code etc. When the application wants + * to call lwIP, it only needs to disable interrupts during the call. + * If timers are involved, even more locking code is needed to lock out + * timer IRQ and ethernet IRQ from each other, assuming these may be nested. + * + * 2) Run lwIP in a mainloop. There is example code here: @ref lwip_nosys. + * lwIP is _ONLY_ called from mainloop callstacks here. The ethernet IRQ + * has to put received telegrams into a queue which is polled in the + * mainloop. Ensure lwIP is _NEVER_ called from an interrupt, e.g. + * some SPI IRQ wants to forward data to udp_send() or tcp_write()! + * + * OS Mode + * ------- + * In OS mode, @ref callbackstyle_api AND @ref sequential_api can be used. + * @ref sequential_api are designed to be called from threads other than + * the TCPIP thread, so there is nothing to consider here. + * But @ref callbackstyle_api functions must _ONLY_ be called from + * TCPIP thread. It is a common error to call these from other threads + * or from IRQ contexts. ​Ethernet RX needs to deliver incoming packets + * in the correct way by sending a message to TCPIP thread, this is + * implemented in tcpip_input().​​ + * Again, ensure lwIP is _NEVER_ called from an interrupt, e.g. + * some SPI IRQ wants to forward data to udp_send() or tcp_write()! + * + * 1) tcpip_callback() can be used get called back from TCPIP thread, + * it is safe to call any @ref callbackstyle_api from there. + * + * 2) Use @ref LWIP_TCPIP_CORE_LOCKING. All @ref callbackstyle_api + * functions can be called when lwIP core lock is aquired, see + * @ref LOCK_TCPIP_CORE() and @ref UNLOCK_TCPIP_CORE(). + * These macros cannot be used in an interrupt context! + * Note the OS must correctly handle priority inversion for this. + */ + /** * @page bugs Reporting bugs * Please report bugs in the lwIP bug tracker at savannah.\n @@ -60,7 +117,7 @@ * to use @ref LWIP_TCPIP_CORE_LOCKING.\n * Porting: implement all functions in @ref sys_layer.\n * You can use @ref callbackstyle_api together with @ref tcpip_callback, - * and all @ref threadsafe_api. + * and all @ref sequential_api. */ /** diff --git a/src/api/api_lib.c b/src/api/api_lib.c index e129473d..99c4b54d 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -3,7 +3,7 @@ * Sequential API External module * * @defgroup netconn Netconn API - * @ingroup threadsafe_api + * @ingroup sequential_api * Thread-safe, to be called from non-TCPIP threads only. * TX/RX handling based on @ref netbuf (containing @ref pbuf) * to avoid copying data around. diff --git a/src/api/netifapi.c b/src/api/netifapi.c index 6f7e55bf..fef05a34 100644 --- a/src/api/netifapi.c +++ b/src/api/netifapi.c @@ -3,7 +3,7 @@ * Network Interface Sequential API module * * @defgroup netifapi NETIF API - * @ingroup threadsafe_api + * @ingroup sequential_api * Thread-safe functions to be called from non-TCPIP threads * * @defgroup netifapi_netif NETIF related diff --git a/src/api/sockets.c b/src/api/sockets.c index 72e777d4..d6455534 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -3,7 +3,7 @@ * Sockets BSD-Like API module * * @defgroup socket Socket API - * @ingroup threadsafe_api + * @ingroup sequential_api * BSD-style socket API.\n * Thread-safe, to be called from non-TCPIP threads only.\n * Can be activated by defining @ref LWIP_SOCKET to 1.\n diff --git a/src/include/lwip/tcpip.h b/src/include/lwip/tcpip.h index 404a4a2c..f2f6b469 100644 --- a/src/include/lwip/tcpip.h +++ b/src/include/lwip/tcpip.h @@ -52,7 +52,9 @@ extern "C" { #if LWIP_TCPIP_CORE_LOCKING /** The global semaphore to lock the stack. */ extern sys_mutex_t lock_tcpip_core; +/** Lock lwIP core mutex (needs @ref LWIP_TCPIP_CORE_LOCKING 1) */ #define LOCK_TCPIP_CORE() sys_mutex_lock(&lock_tcpip_core) +/** Unlock lwIP core mutex (needs @ref LWIP_TCPIP_CORE_LOCKING 1) */ #define UNLOCK_TCPIP_CORE() sys_mutex_unlock(&lock_tcpip_core) #else /* LWIP_TCPIP_CORE_LOCKING */ #define LOCK_TCPIP_CORE()