Page 1 of 1

esp_netif: list lock/unlock

Posted: Tue Apr 06, 2021 9:39 am
by Uto1963
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
  1.  
  2.  static size_t s_esp_netif_counter = 0;
  3.  
  4.  
  5. esp_netif_t *esp_netif_new(const esp_netif_config_t *esp_netif_config)
  6. {
  7.     // mandatory configuration must be provided when creating esp_netif object
  8.     if (esp_netif_config == NULL ||
  9.         esp_netif_config->base->if_key == NULL ||
  10.         NULL != esp_netif_get_handle_from_ifkey(esp_netif_config->base->if_key)) {
  11.         ESP_LOGE(TAG, "%s: Failed to configure netif with config=%p (config or if_key is NULL or duplicate key)",
  12.         __func__,  esp_netif_config);
  13.         return NULL;
  14.     }
  15.  
  16.    …
  17.  
  18. }
  19.  
  20.  
  21. esp_netif_t *esp_netif_get_handle_from_ifkey(const char *if_key)
  22. {
  23.     esp_err_t ret;
  24.     if ((ret = esp_netif_list_lock()) != ESP_OK) {
  25.         ESP_LOGE(TAG, "Failed to lock esp-netif list with %d", ret);
  26.         return NULL;
  27.     }
  28.  
  29.     esp_netif_t *esp_netif = esp_netif_next_unsafe(NULL);
  30.     do {
  31.         if (esp_netif && strcmp(if_key, esp_netif_get_ifkey(esp_netif))==0) {
  32.             esp_netif_list_unlock();
  33.             return esp_netif;
  34.         }
  35.     } while (NULL != (esp_netif = esp_netif_next_unsafe(esp_netif)));
  36.     esp_netif_list_unlock();
  37.     return NULL;
  38. }
  39.  
  40. void esp_netif_list_unlock(void)
  41. {
  42.     assert(s_list_lock);
  43.     xSemaphoreGive(s_list_lock);
  44.     if(s_esp_netif_counter == 0) {
  45.       vQueueDelete(s_list_lock);
  46.       s_list_lock = NULL;
  47.     }
  48. }
  49.  
  50. esp_err_t esp_netif_list_lock(void)
  51. {
  52.     if (s_list_lock == NULL) {
  53.         s_list_lock = xSemaphoreCreateMutex();
  54.         if (s_list_lock == NULL) {
  55.             return ESP_ERR_NO_MEM;
  56.         }
  57.     }
  58.     xSemaphoreTake(s_list_lock, portMAX_DELAY);
  59.     return ESP_OK;
  60. }