mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-31 11:17:20 +02:00
modbus: Exit server task gracefully to correctly cleanup lwip internals
Current lwip implementation does not support deleting a task which is actively waiting on `select()` or `poll()` API. Therefore we have to make sure that `select()` exits to deallocate its internal callback before deleting the task. This is achieved by a shutdown semaphore which informs the client once the `select()` exitted. fix slave
This commit is contained in:
@@ -66,6 +66,7 @@ void vMBPortEventClose( void );
|
|||||||
|
|
||||||
/* ----------------------- Static variables ---------------------------------*/
|
/* ----------------------- Static variables ---------------------------------*/
|
||||||
static int xListenSock = -1;
|
static int xListenSock = -1;
|
||||||
|
static SemaphoreHandle_t xShutdownSemaphore = NULL;
|
||||||
static MbSlavePortConfig_t xConfig = { 0 };
|
static MbSlavePortConfig_t xConfig = { 0 };
|
||||||
|
|
||||||
/* ----------------------- Static functions ---------------------------------*/
|
/* ----------------------- Static functions ---------------------------------*/
|
||||||
@@ -462,6 +463,11 @@ static void vMBTCPPortServerTask(void *pvParameters)
|
|||||||
// Wait for an activity on one of the sockets, timeout is NULL, so wait indefinitely
|
// Wait for an activity on one of the sockets, timeout is NULL, so wait indefinitely
|
||||||
xErr = select(xMaxSd + 1 , &xReadSet , NULL , NULL , NULL);
|
xErr = select(xMaxSd + 1 , &xReadSet , NULL , NULL , NULL);
|
||||||
if ((xErr < 0) && (errno != EINTR)) {
|
if ((xErr < 0) && (errno != EINTR)) {
|
||||||
|
// First check if the task is not flagged for shutdown
|
||||||
|
if (xListenSock == -1 && xShutdownSemaphore) {
|
||||||
|
xSemaphoreGive(xShutdownSemaphore);
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
// error occurred during wait for read
|
// error occurred during wait for read
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "select() errno = %d.", errno);
|
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "select() errno = %d.", errno);
|
||||||
continue;
|
continue;
|
||||||
@@ -626,8 +632,22 @@ void
|
|||||||
vMBTCPPortClose( )
|
vMBTCPPortClose( )
|
||||||
{
|
{
|
||||||
// Release resources for the event queue.
|
// Release resources for the event queue.
|
||||||
|
|
||||||
|
// Try to exit the task gracefully, so select could release its internal callbacks
|
||||||
|
// that were allocated on the stack of the task we're going to delete
|
||||||
|
xShutdownSemaphore = xSemaphoreCreateBinary();
|
||||||
|
vTaskResume(xConfig.xMbTcpTaskHandle);
|
||||||
|
if (xShutdownSemaphore == NULL || // if no semaphore (alloc issues) or couldn't acquire it, just delete the task
|
||||||
|
xSemaphoreTake(xShutdownSemaphore, 2*pdMS_TO_TICKS(CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND)) != pdTRUE) {
|
||||||
|
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Task couldn't exit gracefully within timeout -> abruptly deleting the task");
|
||||||
|
vTaskDelete(xConfig.xMbTcpTaskHandle);
|
||||||
|
}
|
||||||
|
if (xShutdownSemaphore) {
|
||||||
|
vSemaphoreDelete(xShutdownSemaphore);
|
||||||
|
xShutdownSemaphore = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
vMBPortEventClose( );
|
vMBPortEventClose( );
|
||||||
vTaskDelete(xConfig.xMbTcpTaskHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
Reference in New Issue
Block a user