Jump to content

    
Neo_Matrix

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

Recommended Posts

Рассматривал реализацию работы в стеке 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?

Share this post


Link to post
Share on other sites
1 час назад, Neo_Matrix сказал:

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

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

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

Share this post


Link to post
Share on other sites

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

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

 

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)

 

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.