Перейти к содержанию
    

Выделение памяти в LWIP API

Рассматривал реализацию работы в стеке LWIP API, при вызовах API функций LWIP, можно встретить следующий код:

err_t
pppapi_close(ppp_pcb *pcb, u8_t nocarrier)
{
  err_t err;
  PPPAPI_VAR_DECLARE(msg);
  PPPAPI_VAR_ALLOC(msg);

  PPPAPI_VAR_REF(msg).msg.ppp = pcb;
  PPPAPI_VAR_REF(msg).msg.msg.close.nocarrier = nocarrier;
  err = tcpip_api_call(pppapi_do_ppp_close, &PPPAPI_VAR_REF(msg).call);
  PPPAPI_VAR_FREE(msg);
  return err;
}

Внутри макроса PPPAPI_VAR_ALLOC вызывается malloc с соответствующими проверками, далее идет вызов функции tcpip_api_call из контекста задачи TCPIP, после вызывается макрос PPPAPI_VAR_FREE который внутри вызывает free с соответствующими проверками. Из кода видно,что зона видимости(существования) переменной msg ограничивается текущей функцией, соответственно возникает вопрос, для чего создавать переменную в динамической памяти, с возможной фрагментацией оной, если можно просто создать переменную на СТЕКЕ задачи, с такой же областью видимости? Или это необходимо для процессоров с MPU?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Neo_Matrix сказал:

Из кода видно,что зона видимости(существования) переменной msg ограничивается текущей функцией, соответственно возникает вопрос, для чего создавать переменную в динамической памяти, с возможной фрагментацией оной, если можно просто создать переменную на СТЕКЕ задачи, с такой же областью видимости?

Из вашего примера не видно даже что такое msg. Тем более не видна её область видимости (если это переменная). Можно только гадать.

А использование дин.памяти, вместо стека, может быть например для того, чтобы не было необходимости раздувать до огромных значений стеки всех задач, которые будут вызывать эту функцию. И таким образом экономится ОЗУ.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Копировать весь код и содержимое всех макросов достаточно накладно, скопирую основное.

Это структура, внутри нее объединение, так что размер не велик, хотя и выглядит ужасающе.

 

struct pppapi_msg_msg {
  ppp_pcb *ppp;
  union {
#if PPP_NOTIFY_PHASE
    struct {
      ppp_notify_phase_cb_fn notify_phase_cb;
    } setnotifyphasecb;
#endif /* PPP_NOTIFY_PHASE */
#if PPPOS_SUPPORT
    struct {
      struct netif *pppif;
      pppos_output_cb_fn output_cb;
      ppp_link_status_cb_fn link_status_cb;
      void *ctx_cb;
    } serialcreate;
#endif /* PPPOS_SUPPORT */
#if PPPOE_SUPPORT
    struct {
      struct netif *pppif;
      struct netif *ethif;
      const char *service_name;
      const char *concentrator_name;
      ppp_link_status_cb_fn link_status_cb;
      void *ctx_cb;
    } ethernetcreate;
#endif /* PPPOE_SUPPORT */
#if PPPOL2TP_SUPPORT
    struct {
      struct netif *pppif;
      struct netif *netif;
      API_MSG_M_DEF_C(ip_addr_t, ipaddr);
      u16_t port;
#if PPPOL2TP_AUTH_SUPPORT
      const u8_t *secret;
      u8_t secret_len;
#endif /* PPPOL2TP_AUTH_SUPPORT */
      ppp_link_status_cb_fn link_status_cb;
      void *ctx_cb;
    } l2tpcreate;
#endif /* PPPOL2TP_SUPPORT */
    struct {
      u16_t holdoff;
    } connect;
    struct {
      u8_t nocarrier;
    } close;
    struct {
      u8_t cmd;
      void *arg;
    } ioctl;
  } msg;
};

struct pppapi_msg {
  struct tcpip_api_call_data call;
  struct pppapi_msg_msg msg;
};

Это некоторые макросы:

#define PPPAPI_VAR_REF(name)               API_VAR_REF(name)
#define PPPAPI_VAR_DECLARE(name)           API_VAR_DECLARE(struct pppapi_msg, name)
#define PPPAPI_VAR_ALLOC(name)             API_VAR_ALLOC_POOL(struct pppapi_msg, PPPAPI_MSG, name, ERR_MEM)
#define PPPAPI_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC_POOL(struct pppapi_msg, PPPAPI_MSG, name, NULL)
#define PPPAPI_VAR_FREE(name)              API_VAR_FREE_POOL(PPPAPI_MSG, name)
  
#define API_VAR_REF(name)               (*(name))
#define API_VAR_DECLARE(type, name)     type * name
#define API_VAR_ALLOC_EXT(type, pool, name, errorblock) do { \
                                          name = (type *)memp_malloc(pool); \
                                          if (name == NULL) { \
                                            errorblock; \
                                          } \
                                        } while(0)
#define API_VAR_ALLOC(type, pool, name, errorval) API_VAR_ALLOC_EXT(type, pool, name, return errorval)
#define API_VAR_ALLOC_POOL(type, pool, name, errorval) do { \
                                          name = (type *)LWIP_MEMPOOL_ALLOC(pool); \
                                          if (name == NULL) { \
                                            return errorval; \
                                          } \
                                        } while(0)
#define API_VAR_FREE(pool, name)        memp_free(pool, name)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Также иногда бывает необходимость в буфере в определённой памяти. Например - в памяти, с которой может работать DMA-контроллер (или ETHERNET-контроллер). А стеки задач могут находится например в TCM-памяти (к которой эта периферия не имеет доступа).

Либо МК уходит в сон, а стек задачи находится в памяти, которая недоступна во сне, а периферия (для которрой выделяется память) должна продолжать работать и во сне.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо. В целом так и предполагал, просто первое что пришло на ум, это MPU

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...