esp_netif: list lock/unlock
Posted: Tue Apr 06, 2021 9:39 am
ESP-IDF V4.2
Two threads call esp_netif_new(), that calls esp_netif_get_handle_from_ifkey(), that calls esp_netif_list_lock()
The first thread creates and takes the semaphore; the second waits for xSemaphoreTake() returning.
The first threads gives the semaphore then delete it, beeing s_esp_netif_counter still zero.
When the second thread calls esp_netif_unlock() assert(s_list_lock) fails beeing the semaphore handle NULL.
The semaphore cannot protect itself.
Code from esp_netif_objects.c
Two threads call esp_netif_new(), that calls esp_netif_get_handle_from_ifkey(), that calls esp_netif_list_lock()
The first thread creates and takes the semaphore; the second waits for xSemaphoreTake() returning.
The first threads gives the semaphore then delete it, beeing s_esp_netif_counter still zero.
When the second thread calls esp_netif_unlock() assert(s_list_lock) fails beeing the semaphore handle NULL.
The semaphore cannot protect itself.
Code from esp_netif_objects.c
Code: Untitled.c Select all
static size_t s_esp_netif_counter = 0;
esp_netif_t *esp_netif_new(const esp_netif_config_t *esp_netif_config)
{
// mandatory configuration must be provided when creating esp_netif object
if (esp_netif_config == NULL ||
esp_netif_config->base->if_key == NULL ||
NULL != esp_netif_get_handle_from_ifkey(esp_netif_config->base->if_key)) {
ESP_LOGE(TAG, "%s: Failed to configure netif with config=%p (config or if_key is NULL or duplicate key)",
__func__, esp_netif_config);
return NULL;
}
…
}
esp_netif_t *esp_netif_get_handle_from_ifkey(const char *if_key)
{
esp_err_t ret;
if ((ret = esp_netif_list_lock()) != ESP_OK) {
ESP_LOGE(TAG, "Failed to lock esp-netif list with %d", ret);
return NULL;
}
esp_netif_t *esp_netif = esp_netif_next_unsafe(NULL);
do {
if (esp_netif && strcmp(if_key, esp_netif_get_ifkey(esp_netif))==0) {
esp_netif_list_unlock();
return esp_netif;
}
} while (NULL != (esp_netif = esp_netif_next_unsafe(esp_netif)));
esp_netif_list_unlock();
return NULL;
}
void esp_netif_list_unlock(void)
{
assert(s_list_lock);
xSemaphoreGive(s_list_lock);
if(s_esp_netif_counter == 0) {
vQueueDelete(s_list_lock);
s_list_lock = NULL;
}
}
esp_err_t esp_netif_list_lock(void)
{
if (s_list_lock == NULL) {
s_list_lock = xSemaphoreCreateMutex();
if (s_list_lock == NULL) {
return ESP_ERR_NO_MEM;
}
}
xSemaphoreTake(s_list_lock, portMAX_DELAY);
return ESP_OK;
}