<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                在內核初始化時,會事先在內存中初始化相應的內存池,內核會將所有可用的區域根據宏定義的配置以固定的大小為單位進行劃分,然后用一個簡單的鏈表將所有空閑塊連接起來,這樣子就組成一個個的內存池。由于鏈表中所有節點的大小相同,所以分配時不需要查找,直接取出第一個節點中的空間分配給用戶即可。 注意了,內核在初始化內存池的時候,是根據用戶配置的宏定義進行初始化的,比如,用戶定義了LWIP\_UDP這個宏定義,在編譯的時候,編譯器就會將與UDP協議控制塊相關的數據構編譯編譯進去,這樣子就將LWIP\_MEMPOOL(UDP\_PCB, MEMP\_NUM\_UDP\_PCB, sizeof(struct udp\_pcb),"UDP\_PCB")包含進去,在初始化的時候,UDP協議控制塊需要的POOL資源就會被初始化,其數量由MEMP\_NUM\_UDP\_PCB宏定義決定,注意了,不同協議的POOL內存塊的大小是不一樣的,這由協議的性質決定,如UDP協議控制塊的內存塊大小是sizeof(struct udp\_pcb),而TCP協議控制塊的POOL大小則為sizeof(struct tcp\_pcb)。通過這種方式,就可以將一個個用戶配置的宏定義功能需要的POOL包含進去,就使得編程變得更加簡便。 在這里有一個很有意思的文件,那就是memp\_std.h文件,該文件位于include/lwip/priv目錄下,它里面全是宏定義,LwIP為什么要這樣子寫呢,其實很簡單,當然是為了方便,在不同的地方調用#include "lwip/priv/memp\_std.h"就能產生不同的效果。 該文件中的宏值定義全部依賴于宏LWIP\_MEMPOOL(name,num,size,desc),這樣,只要外部提供的該宏值不同,則包含該文件的源文件在編譯器的預處理后,就會產生不一樣的結果。這樣,就可以通過在不同的地方多次包含該文件,前面必定提供宏值MEMPOOL以產生不同結果。可能有些人看得一臉懵逼,其實我一開始也是這樣子,不得不說LwIP源碼的作者還是很厲害的。 簡單來說,就是在外邊提供LWIP\_MEMPOOL宏定義,然后在包含memp\_std.h文件,編譯器就會幫我們處理,我們先來看看memp\_std.h文件到底有什么內容,具體見代碼清單 5?1,再舉個簡單的例子說明一下,具體見代碼清單 5?2。 ``` 1 #if LWIP_RAW 2 LWIP_MEMPOOL(RAW_PCB, MEMP_NUM_RAW_PCB, 3 sizeof(struct raw_pcb), "RAW_PCB") 4 #endif /* LWIP_RAW */ 5 6 #if LWIP_UDP 7 LWIP_MEMPOOL(UDP_PCB, MEMP_NUM_UDP_PCB, 8 sizeof(struct udp_pcb), "UDP_PCB") 9 #endif /* LWIP_UDP */ 10 11 #if LWIP_TCP 12 LWIP_MEMPOOL(TCP_PCB, MEMP_NUM_TCP_PCB, 13 sizeof(struct tcp_pcb), "TCP_PCB") 14 15 LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN, 16 sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN") 17 18 LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, 19 sizeof(struct tcp_seg), "TCP_SEG") 20 #endif /* LWIP_TCP */ 21 22 #if LWIP_ALTCP && LWIP_TCP 23 LWIP_MEMPOOL(ALTCP_PCB, MEMP_NUM_ALTCP_PCB, 24 sizeof(struct altcp_pcb), "ALTCP_PCB") 25 #endif /* LWIP_ALTCP && LWIP_TCP */ 26 27 #if LWIP_IPV4 && IP_REASSEMBLY 28 LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, 29 sizeof(struct ip_reassdata), "REASSDATA") 30 #endif /* LWIP_IPV4 && IP_REASSEMBLY */ 31 32 #if LWIP_NETCONN || LWIP_SOCKET 33 LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, 34 sizeof(struct netbuf), "NETBUF") 35 36 LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, 37 sizeof(struct netconn), "NETCONN") 38 #endif /* LWIP_NETCONN || LWIP_SOCKET */ 39 #undef LWIP_MEMPOOL ``` memp_std.h使用方式的例子 ``` 1 typedef enum 2 { 3 #define LWIP_MEMPOOL(name,num,size,desc) MEMP_##name, 4 #include "lwip/priv/memp_std.h" 5 MEMP_MAX 6 } memp_t; ``` 可能很多人一看到代碼清單 5?2的例子,就懵逼了,這寫的是什么鬼東西,完全不知道LwIP作者想要干什么,但是當你讀懂這段代碼的時候,你就不得不佩服LwIP作者的水平了,那是真的厲害。 先說說“#define LWIP\_MEMPOOL(name,num,size,desc) MEMP\_##name,”這個宏定義,此處先補充一下C語言的連接符“##”相關的知識,##被稱為連接符(concatenator),用來將兩個Token連接為一個Token。注意這里連接的對象是Token就行,而不一定是宏的變量。在編譯器編譯的時候,它會掃描源碼,將代碼分解為一個個的Token,Token可以是C語言的關鍵字,如int、for、while等,也可以是用戶自定義的變量,如,a、num、name等,當我們經過“#define LWIP\_MEMPOOL(name,num,size,desc) MEMP\_##name,”這個宏定義后,在編譯過程中遇到了“LWIP\_MEMPOOL(EmbedFire,num,size,desc)”這句代碼,編譯器就會將它替換為“MEMP\_EmbedFire,”注意,這里有一個英文的逗號“,”,因為現在是定義枚舉類型的數據,那么經過編譯器處理的代碼清單 5?2代碼后,這個枚舉變量就會變成以下的內容(假設所有的宏定義都是使能狀態),具體見代碼清單 5?3。 ``` 1 typedef enum 2 { 3 MEMP_RAW_PCB, 4 MEMP_UDP_PCB, 5 MEMP_TCP_PCB, 6 MEMP_TCP_PCB_LISTEN, 7 MEMP_TCP_SEG, 8 MEMP_ALTCP_PCB, 9 MEMP_REASSDATA, 10 MEMP_NETBUF, 11 MEMP_NETCONN, 12 MEMP_MAX 13 } memp_t; ``` memp\_t類型在整個內存池的管理中是最重要的存在,通過內存池申請函數申請內存的時候,唯一的參數就是memp\_t類型的,它將告訴分配的函數在哪種類型的POOL中去分配對應的內存塊,這樣子就直接管理了系統中所有類型的POOL。 這個枚舉變量的MEMP\_MAX不代表任何類型的POOL,它只是記錄這系統中所有的POOL的數量,比如例子中的MEMP\_RAW\_PCB 的值為0,而MEMP\_MAX的值為9,就表示當前系統中有9種POOL。 理解了這樣子的編程,是不是大開眼界了?不過還有一點需要注意的是,在memp\_std.h文件的最后需要對LWIP\_MEMPOOL宏定義進行撤銷,因為該文件很會被多個地方調用,在每個調用的地方會重新定義這個宏定義的功能,所以在文件的末尾添加這句#undef LWIP\_MEMPOOL代碼是非常有必要的。 在這里還要給大家提個醒,如果以后看LwIP源碼的時候,發現某個找不到定義,但是編譯是沒有問題的,那么很可能就是通過“##”連接符產生的宏定義了,例如圖 5?2出現的情況,MEMP\_RAW\_PCB定義就在memp\_t類型中,是通過“##”連接符產生的。 ![](https://box.kancloud.cn/eeb5f3a3c05707aaf283925eac8955ab_581x61.png) 圖 5?2未找到MEMP\_RAW\_PCB的定義 按照這種包含頭文件的原理,只需要定義LWIP\_MEMPOOL宏的作用,就能產生很大與內存池相關的操作,如在memp.c文件的開頭就定義了如下代碼: ``` 1 #define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc) 2 #include "lwip/priv/memp_std.h" ``` 經過包含memp\_std.h文件后,再經過編譯器的處理,就能得到下面的結果,具體見代碼清單 5?5加粗部分。其實這些編譯器處理的代碼我們并不需要怎么理會,簡單了解一下即可. ``` 1 #define LWIP_MEMPOOL(name,num,size,desc) \ 2 LWIP_MEMPOOL_DECLARE(name,num,size,desc) 3 4 #define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) \ 5 u8_t variable_name[LWIP_MEM_ALIGN_BUFFER(size)] 6 7 LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1U)) 8 9 #define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \ 10 LWIP_DECLARE_MEMORY_ALIGNED(memp_memory_ ## name ## _base, \ 11 ((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))); \ 12 \ 13 LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(memp_stats_ ## name) \ 14 \ 15 static struct memp *memp_tab_ ## name; \ 16 \ 17 const struct memp_desc memp_ ## name = { \ 18 DECLARE_LWIP_MEMPOOL_DESC(desc) \ 19 LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(memp_stats_ ## name) \ 20 LWIP_MEM_ALIGN_SIZE(size), \ 21 (num), \ 22 memp_memory_ ## name ## _base, \ 23 &memp_tab_ ## name \ 24 }; 25 26 /* 編譯時候的宏定義 */ 27 LWIP_MEMPOOL(RAW_PCB,MEMP_NUM_RAW_PCB,sizeof(struct raw_pcb),"RAW_PCB") 28 29 /* 通過轉換后得到的結果,例子是 RAW_PCB */ 30 LWIP_DECLARE_MEMORY_ALIGNED(memp_memory_RAW_PCB_base, 31 ((MEMP_NUM_RAW_PCB) * (MEMP_SIZE + MEMP_ALIGN_SIZE(sizeof(struct raw_pcb))))); 32 33 LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(memp_stats_RAW_PCB) 34 35 static struct memp *memp_tab_RAW_PCB; 36 37 const struct memp_desc memp_RAW_PCB = 38 { 39 DECLARE_LWIP_MEMPOOL_DESC("RAW_PCB") 40 LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(memp_stats_RAW_PCB) 41 LWIP_MEM_ALIGN_SIZE(sizeof(struct raw_pcb)), 42 (MEMP_NUM_RAW_PCB), 43 memp_memory_RAW_PCB_base, 44 &memp_tab_RAW_PCB 45 }; 46 47 /* 再次轉換 */ 48 u8_t memp_memory_RAW_PCB_base[(((((MEMP_NUM_RAW_PCB) * 49 (MEMP_SIZE + MEMP_ALIGN_SIZE(sizeof(struct raw_pcb))))) 50 + MEM_ALIGNMENT - 1U))]; 51 52 static struct memp *memp_tab_RAW_PCB; 53 54 const struct memp_desc memp_RAW_PCB ={ 55 (((sizeof(struct raw_pcb)) + MEM_ALIGNMENT - 1U) & ~(MEM_ALIGNMENT-1U)), 56 LWIP_MEM_ALIGN_SIZE(sizeof(struct raw_pcb)), 57 (MEMP_NUM_RAW_PCB), 58 memp_memory_RAW_PCB_base, 59 &memp_tab_RAW_PCB 60 }; 61 62 /* 代入數據得到,注意,數據是根據自己配置的宏定義得到的 */ 63 u8_t memp_memory_RAW_PCB_base[((4 * 24) + 4 - 1U)]; 64 65 static struct memp *memp_tab_RAW_PCB; 66 67 const struct memp_desc memp_RAW_PCB ={ 68 ((24) + 4 - 1U) & ~(4-1U)), 69 (24), 70 4 71 memp_memory_RAW_PCB_base, 72 &memp_tab_RAW_PCB 73 }; ``` 關于包含memp_std.h文件的處理就不再過多說明了,用戶也不需要了解太多,我們就來看看關于內存池的主要參數,就使用上面的RAW_PCB的例子,每種POOL在經過編譯器都會得到一個結構體,memp_desc memp_XXXX,XXXX表示對應的POOL類型,如RAW_PCB的結構體就是memp_desc memp_RAW_PCB,這里面就記錄了該內存塊對其后的大小LWIP_MEM_ALIGN_SIZE(sizeof(struct raw_pcb))。也就是說,在經過編譯器的處理,該結構體就保存了每種POOL的內存對齊后的大小。 同理該結構體也記錄了每種POOL的其他參數,如內存塊的個數num,比如MEMP_NUM_RAW_PCB,這些就是用戶配置的宏定義,都會被記錄在里面,還有每種POOL的描述 “DECLARE_LWIP_MEMPOOL_DESC("RAW_PCB")”,當然這個參數可用可不用,這只是一個字符串,在輸出信息的時候用到。 除了這些信息,還有一個最重要的信息,那就是真正的內存池區域,使用u8_t memp_memory_XXXX_base進行定義,XXXX表示對應的POOL類型,每個類型都有自己的內存池區域,是編譯器開辟出來的內存空間,簡單來說就是一個數組,我們知道這個區域的的起始地址,就能對它進行操作。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看