diff --git a/components/lwip/port/freertos/sys_arch.c b/components/lwip/port/freertos/sys_arch.c index 8d0dd08c58..97ee32d1bd 100755 --- a/components/lwip/port/freertos/sys_arch.c +++ b/components/lwip/port/freertos/sys_arch.c @@ -42,6 +42,9 @@ /* This is the number of threads that can be started with sys_thread_new() */ #define SYS_THREAD_MAX 4 +static bool g_lwip_in_critical_section = false; +static BaseType_t g_lwip_critical_section_needs_taskswitch; + #if !LWIP_COMPAT_MUTEX /** Create a new mutex * @param mutex pointer to the mutex to create @@ -122,7 +125,18 @@ sys_sem_new(sys_sem_t *sem, u8_t count) void sys_sem_signal(sys_sem_t *sem) { - xSemaphoreGive(*sem); + if (g_lwip_in_critical_section){ + /* In function event_callback in sockets.c, lwip signals a semaphore inside a critical + * section. According to the FreeRTOS documentation for FreertosTaskEnterCritical, it's + * not allowed to call any FreeRTOS API function within a critical region. Unfortunately, + * it's not feasible to rework the affected region in LWIP. As a solution, when in a + * critical region, we call xSemaphoreGiveFromISR. This routine is hand-vetted to work + * in a critical region and it will not cause a task switch. + */ + xSemaphoreGiveFromISR(*sem, &g_lwip_critical_section_needs_taskswitch); + } else { + xSemaphoreGive(*sem); + } } /*-----------------------------------------------------------------------------------*/ @@ -453,6 +467,7 @@ sys_prot_t sys_arch_protect(void) { portENTER_CRITICAL(&g_lwip_mux); + g_lwip_in_critical_section = true; return (sys_prot_t) 1; } @@ -467,7 +482,12 @@ void sys_arch_unprotect(sys_prot_t pval) { (void) pval; + g_lwip_in_critical_section = false; portEXIT_CRITICAL(&g_lwip_mux); + if (g_lwip_critical_section_needs_taskswitch){ + g_lwip_critical_section_needs_taskswitch = 0; + portYIELD(); + } } /*-----------------------------------------------------------------------------------*/