<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移植的核心就是編寫與操作系統相關的接口文件sys\_arch.c和sys\_arch.h,這兩個文件可以自己創建也可以從contrib包中獲取,路徑分別為“contrib-2.1.0\\ports\\freertos”與“contrib-2.1.0\\ports\\freertos\\include\\arch”,用戶在移植的時候必須根據操作系統的功能為協議棧提供相應的接口,如郵箱(因為本次移植以FreeRTOS為例子,FreeRTOS中沒有郵箱這種概念,但是可以使用消息隊列替代,為了迎合LwIP中的命名,下文統一采用郵箱表示)、信號量、互斥量等,這些IPC通信機制是保證內核與上層API接口通信的基本保障,也是內核實現管理的繼承,同時在sys.h文件中聲明了用戶需要實現的所有函數框架,這些函數具體見表格 8?2。 | 名稱 | 屬性 | 功能 | 所在文件 | | --- | --- | --- | --- | | sys\_sem\_t | 數據類型 | 指針類型,指向系統信號量 | sys\_arch.h | | sys\_mutex\_t | 數據類型 | 指針類型,指向系統互斥量 | sys\_arch.h | | sys\_mbox\_t | 數據類型 | 指針類型,指向系統郵箱 | sys\_arch.h | | sys\_thread\_t | 數據類型 | 指針類型,指向系統任務 | sys\_arch.h | | SYS\_MBOX\_NULL | 宏定義 | 系統郵箱的空值 | sys\_arch.h | | SYS\_SEM\_NULL | 宏定義 | 系統信號量的空值 | sys\_arch.h | | SYS\_MRTEX\_NULL | 宏定義 | 系統互斥量的空值 | sys\_arch.h | | sys\_now | 函數 | 內核時鐘 | sys\_arch.c | | sys\_init | 函數 | 初始化系統 | sys\_arch.c | | sys\_arch\_protect | 函數 | 進入臨界段 | sys\_arch.c | | sys\_arch\_unprotect | 函數 | 退出臨界段 | sys\_arch.c | | sys\_sem\_new | 函數 | 創建一個信號量 | sys\_arch.c | | sys\_sem\_free | 函數 | 刪除一個信號量 | sys\_arch.c | | sys\_sem\_valid | 函數 | 判斷信號量是否有效 | sys\_arch.c | | sys\_sem\_set\_invalid | 函數 | 將信號量設置無效狀態 | sys\_arch.c | | sys\_arch\_sem\_wait | 函數 | 等待一個信號量 | sys\_arch.c | | sys\_sem\_signal | 函數 | 釋放一個信號量 | sys\_arch.c | | sys\_mutex\_new | 函數 | 創建一個互斥量 | sys\_arch.c | | sys\_mutex\_free | 函數 | 刪除一個互斥量 | sys\_arch.c | | sys\_mutex\_set\_invalid | 函數 | 設置互斥量為無效狀態 | sys\_arch.c | | sys\_mutex\_lock | 函數 | 獲取一個互斥量 | sys\_arch.c | | sys\_mutex\_unlock | 函數 | 釋放一個互斥量 | sys\_arch.c | | sys\_mbox\_new | 函數 | 創建一個郵箱 | sys\_arch.c | | sys\_mbox\_free | 函數 | 刪除一個郵箱 | sys\_arch.c | | sys\_mbox\_valid | 函數 | 判斷郵箱是否有效 | sys\_arch.c | | sys\_mbox\_set\_invalid | 函數 | 設置郵箱為無效狀態 | sys\_arch.c | | sys\_mbox\_post | 函數 | 向郵箱發送消息,一直阻塞 | sys\_arch.c | | sys\_mbox\_trypost | 函數 | 向郵箱發送消息,非阻塞 | sys\_arch.c | | sys\_mbox\_trypost\_fromisr | 函數 | 在中斷中向郵箱發送消息 | sys\_arch.c | | sys\_arch\_mbox\_fetch | 函數 | 從郵箱中獲取消息,阻塞 | sys\_arch.c | | sys\_arch\_mbox\_tryfetch | 函數 | 從郵箱中獲取消息,非阻塞 | sys\_arch.c | | sys\_thread\_new | 函數 | 創建一個線程 | sys\_arch.c | 看到那么多函數,是不是頭都大了,其實這些函數的實現都是很簡單的,首先講解一下郵箱函數的實現。在LwIP中,用戶代碼與協議棧內部之間是通過郵箱進行數據的交互的,郵箱本質上就是一個指向數據的指針,API將指針傳遞給內核,內核通過這個指針訪問數據,然后去處理,反之內核將數據傳遞給用戶代碼也是通過郵箱將一個指針進行傳遞。 在操作系統環境下,LwIP會作為一個線程運行,線程的名字叫tcpip\_thread,在初始化LwIP的時候,內核就會自動創建這個線程,并且在線程運行的時候阻塞在郵箱上,等待數據進行處理,這個郵箱數據的來源可能在底層網卡接收到的數據或者上層應用程序的數據,總之,tcpip\_thread線程在獲取到郵箱中的數據時候,就會退出阻塞態,去處理數據,在處理完畢數據后又進入阻塞態中等待數據的到來,如此反復。 信號量與互斥量的實現為內核提供同步與互斥的機制,比如當用戶想要發送一個數據的時候,就會調用上層API接口,API接口就會去先發送一個數據給內核去處理,然后嘗試獲取一個信號量,因為此時是沒有信號量的,所以就會阻塞用戶線程;內核在知道用戶想要發送數據后,就會調用對應的網卡去發送數據,當數據發送完成后就釋放一個信號量告知用戶線程發送完成,這樣子用戶線程就得以繼續執行。 所以這些函數的接口都必須由用戶實現,下面具體看看這些函數的實現,具體見代碼清單 8?3。 ``` 1 #include "debug.h" 2 3 #include <lwip/opt.h> 4 #include <lwip/arch.h> 5 6 #include "tcpip.h" 7 #include "lwip/init.h" 8 #include "lwip/netif.h" 9 #include "lwip/sio.h" 10 #include "ethernetif.h" 11 12 #if !NO_SYS 13 #include "sys_arch.h" 14 #endif 15 #include <lwip/stats.h> 16 #include <lwip/debug.h> 17 #include <lwip/sys.h> 18 19 #include <string.h> 20 21 int errno; 22 23 24 u32_t lwip_sys_now; 25 26 struct sys_timeouts 27 { 28 struct sys_timeo *next; 29 }; 30 31 struct timeoutlist 32 { 33 struct sys_timeouts timeouts; 34 xTaskHandle pid; 35 }; 36 37 #define SYS_THREAD_MAX 4 38 39 static struct timeoutlist s_timeoutlist[SYS_THREAD_MAX]; 40 41 static u16_t s_nextthread = 0; 42 43 u32_t 44 sys_jiffies(void) 45 { 46 lwip_sys_now = xTaskGetTickCount(); 47 return lwip_sys_now; 48 } 49 50 u32_t 51 sys_now(void) 52 { 53 lwip_sys_now = xTaskGetTickCount(); 54 return lwip_sys_now; 55 } 56 57 void 58 sys_init(void) 59 { 60 int i; 61 // Initialize the the per-thread sys_timeouts structures 62 // make sure there are no valid pids in the list 63 for (i = 0; i < SYS_THREAD_MAX; i++) 64 { 65 s_timeoutlist[i].pid = 0; 66 s_timeoutlist[i].timeouts.next = NULL; 67 } 68 // keep track of how many threads have been created 69 s_nextthread = 0; 70 } 71 72 struct sys_timeouts *sys_arch_timeouts(void) 73 { 74 int i; 75 xTaskHandle pid; 76 struct timeoutlist *tl; 77 pid = xTaskGetCurrentTaskHandle( ); 78 for (i = 0; i < s_nextthread; i++) 79 { 80 tl = &(s_timeoutlist[i]); 81 if (tl->pid == pid) 82 { 83 return &(tl->timeouts); 84 } 85 } 86 return NULL; 87 } 88 89 sys_prot_t sys_arch_protect(void) 90 { 91 vPortEnterCritical(); //進入臨界段 92 return 1; 93 } 94 95 void sys_arch_unprotect(sys_prot_t pval) 96 { 97 ( void ) pval; 98 vPortExitCritical(); //退出臨界段 99 } 100 101 #if !NO_SYS 102 103 err_t 104 sys_sem_new(sys_sem_t *sem, u8_t count) 105 { 106 /* 創建 sem */ 107 if (count <= 1) 108 { 109 *sem = xSemaphoreCreateBinary(); //創建二值信號量 110 if (count == 1) 111 { 112 sys_sem_signal(*sem); //新創建的信號量是無效的,需要釋放一個信號量 113 } 114 } 115 else 116 *sem = xSemaphoreCreateCounting(count,count); //創建計數信號量 117 118 #if SYS_STATS 119 ++lwip_stats.sys.sem.used; 120 if (lwip_stats.sys.sem.max < lwip_stats.sys.sem.used) 121 { 122 lwip_stats.sys.sem.max = lwip_stats.sys.sem.used; 123 } 124 #endif /* SYS_STATS */ 125 126 if (*sem != SYS_SEM_NULL) 127 return ERR_OK; //創建成功返回ERR_OK 128 else 129 { 130 #if SYS_STATS 131 ++lwip_stats.sys.sem.err; 132 #endif /* SYS_STATS */ 133 printf("[sys_arch]:new sem fail!\n"); 134 return ERR_MEM; 135 } 136 } 137 138 void 139 sys_sem_free(sys_sem_t *sem) 140 { 141 #if SYS_STATS 142 --lwip_stats.sys.sem.used; 143 #endif /* SYS_STATS */ 144 /* 刪除 sem */ 145 vSemaphoreDelete(*sem); //刪除一個信號量 146 *sem = SYS_SEM_NULL; //刪除之后置空 147 } 148 149 150 int sys_sem_valid(sys_sem_t *sem) 151 { 152 return (*sem != SYS_SEM_NULL); //返回信號量是否有效 153 } 154 155 156 void 157 sys_sem_set_invalid(sys_sem_t *sem) 158 { 159 *sem = SYS_SEM_NULL; //信號量設置為無效 160 } 161 162 /* 163 如果timeout參數不為零,則返回值為 164 等待信號量所花費的毫秒數。如果 165 信號量未在指定時間內發出信號,返回值為 166 SYS_ARCH_TIMEOUT。如果線程不必等待信號量 167 該函數返回零。 */ 168 u32_t 169 sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) 170 { 171 u32_t wait_tick = 0; 172 u32_t start_tick = 0 ; 173 174 //看看信號量是否有效 175 if (*sem == SYS_SEM_NULL) 176 return SYS_ARCH_TIMEOUT; 177 178 //首先獲取開始等待信號量的時鐘節拍 179 start_tick = xTaskGetTickCount(); 180 181 //timeout != 0,需要將ms換成系統的時鐘節拍 182 if (timeout != 0) 183 { 184 //將ms轉換成時鐘節拍 185 wait_tick = timeout / portTICK_PERIOD_MS; 186 if (wait_tick == 0) 187 wait_tick = 1; 188 } 189 else 190 wait_tick = portMAX_DELAY; //一直阻塞 191 192 //等待成功,計算等待的時間,否則就表示等待超時 193 if (xSemaphoreTake(*sem, wait_tick) == pdTRUE) 194 return ((xTaskGetTickCount()-start_tick)*portTICK_RATE_MS); 195 else 196 return SYS_ARCH_TIMEOUT; 197 } 198 199 void 200 sys_sem_signal(sys_sem_t *sem) 201 { 202 if (xSemaphoreGive( *sem ) != pdTRUE) //釋放信號量 203 printf("[sys_arch]:sem signal fail!\n"); 204 } 205 206 err_t 207 sys_mutex_new(sys_mutex_t *mutex) 208 { 209 /* 創建 sem */ 210 *mutex = xSemaphoreCreateMutex(); //創建互斥量 211 if (*mutex != SYS_MRTEX_NULL) 212 return ERR_OK; //創建成功返回ERR_OK 213 else 214 { 215 printf("[sys_arch]:new mutex fail!\n"); 216 return ERR_MEM; 217 } 218 } 219 220 void 221 sys_mutex_free(sys_mutex_t *mutex) 222 { 223 vSemaphoreDelete(*mutex); //刪除互斥量 224 } 225 226 void 227 sys_mutex_set_invalid(sys_mutex_t *mutex) 228 { 229 *mutex = SYS_MRTEX_NULL; //設置互斥量為無效 230 } 231 232 void 233 sys_mutex_lock(sys_mutex_t *mutex) 234 { 235 xSemaphoreTake(*mutex,/* 互斥量句柄 */ 236 portMAX_DELAY); /* 等待時間 */ 237 } 238 239 void 240 sys_mutex_unlock(sys_mutex_t *mutex) 241 { 242 xSemaphoreGive( *mutex );//給出互斥量 243 } 244 245 sys_thread_t 246 sys_thread_new(const char *name, lwip_thread_fn function, 247 void *arg, int stacksize, int prio) 248 { 249 sys_thread_t handle = NULL; 250 BaseType_t xReturn = pdPASS; 251 /* 創建一個線程 */ 252 xReturn = xTaskCreate((TaskFunction_t )function, /* 線程入口函數 */ 253 (const char* )name,/* 線程名字 */ 254 (uint16_t )stacksize, /* 線程棧大小 */ 255 (void* )arg,/* 線程入口函數參數 */ 256 (UBaseType_t )prio, /* 線程的優先級 */ 257 (TaskHandle_t* )&handle);/* 線程控制塊指針 */ 258 if (xReturn != pdPASS) 259 { 260 printf("[sys_arch]:create task fail!err:%#lx\n",xReturn); 261 return NULL; 262 } 263 return handle; 264 } 265 266 err_t 267 sys_mbox_new(sys_mbox_t *mbox, int size) 268 { 269 /* 創建一個郵箱 */ 270 *mbox = xQueueCreate((UBaseType_t ) size,/* 郵箱的長度 */ 271 (UBaseType_t ) sizeof(void *));/* 消息的大小 */ 272 #if SYS_STATS 273 ++lwip_stats.sys.mbox.used; 274 if (lwip_stats.sys.mbox.max < lwip_stats.sys.mbox.used) 275 { 276 lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used; 277 } 278 #endif /* SYS_STATS */ 279 if (NULL == *mbox) 280 return ERR_MEM; // 創建成功返回ERR_OK 281 282 return ERR_OK; 283 } 284 285 void 286 sys_mbox_free(sys_mbox_t *mbox) 287 { 288 if ( uxQueueMessagesWaiting( *mbox ) ) 289 { 290 /* Line for breakpoint. Should never break here! */ 291 portNOP(); 292 #if SYS_STATS 293 lwip_stats.sys.mbox.err++; 294 #endif /* SYS_STATS */ 295 } 296 297 vQueueDelete(*mbox); //刪除一個郵箱 298 299 #if SYS_STATS 300 --lwip_stats.sys.mbox.used; 301 #endif /* SYS_STATS */ 302 } 303 304 int sys_mbox_valid(sys_mbox_t *mbox) 305 { 306 if (*mbox == SYS_MBOX_NULL) //判斷郵箱是否有效 307 return 0; 308 else 309 return 1; 310 } 311 312 void 313 sys_mbox_set_invalid(sys_mbox_t *mbox) 314 { 315 *mbox = SYS_MBOX_NULL; //設置有效為無效狀態 316 } 317 318 void 319 sys_mbox_post(sys_mbox_t *q, void *msg) 320 { 321 while (xQueueSend( *q, /* 郵箱的句柄 */ 322 &msg,/* 發送的消息內容 */ 323 portMAX_DELAY) != pdTRUE); /* 等待時間 */ 324 } 325 326 err_t 327 sys_mbox_trypost(sys_mbox_t *q, void *msg) 328 { 329 if (xQueueSend(*q,&msg,0) == pdPASS) //嘗試發送一個消息,非阻塞發送 330 return ERR_OK; 331 else 332 return ERR_MEM; 333 } 334 335 err_t 336 sys_mbox_trypost_fromisr(sys_mbox_t *q, void *msg) 337 { 338 uint32_t ulReturn; 339 err_t err = ERR_MEM; 340 BaseType_t pxHigherPriorityTaskWoken; 341 342 /* 進入臨界段,臨界段可以嵌套 */ 343 ulReturn = taskENTER_CRITICAL_FROM_ISR(); 344 345 if (xQueueSendFromISR(*q,&msg,&pxHigherPriorityTaskWoken)==pdPASS) 346 { 347 err = ERR_OK; 348 } 349 //如果需要的話進行一次線程切換 350 portYIELD_FROM_ISR(pxHigherPriorityTaskWoken); 351 352 /* 退出臨界段 */ 353 taskEXIT_CRITICAL_FROM_ISR( ulReturn ); 354 355 return err; 356 } 357 358 u32_t 359 sys_arch_mbox_fetch(sys_mbox_t *q, void **msg, u32_t timeout) 360 { 361 void *dummyptr; 362 u32_t wait_tick = 0; 363 u32_t start_tick = 0 ; 364 365 if ( msg == NULL ) //看看存儲消息的地方是否有效 366 msg = &dummyptr; 367 368 //首先獲取開始等待信號量的時鐘節拍 369 start_tick = sys_now(); 370 371 //timeout != 0,需要將ms換成系統的時鐘節拍 372 if (timeout != 0) 373 { 374 //將ms轉換成時鐘節拍 375 wait_tick = timeout / portTICK_PERIOD_MS; 376 if (wait_tick == 0) 377 wait_tick = 1; 378 } 379 //一直阻塞 380 else 381 wait_tick = portMAX_DELAY; 382 383 //等待成功,計算等待的時間,否則就表示等待超時 384 if (xQueueReceive(*q,&(*msg), wait_tick) == pdTRUE) 385 return ((sys_now() - start_tick)*portTICK_PERIOD_MS); 386 else 387 { 388 *msg = NULL; 389 return SYS_ARCH_TIMEOUT; 390 } 391 } 392 393 u32_t 394 sys_arch_mbox_tryfetch(sys_mbox_t *q, void **msg) 395 { 396 void *dummyptr; 397 if ( msg == NULL ) 398 msg = &dummyptr; 399 400 //等待成功,計算等待的時間 401 if (xQueueReceive(*q,&(*msg), 0) == pdTRUE) 402 return ERR_OK; 403 else 404 return SYS_MBOX_EMPTY; 405 } 406 407 #if LWIP_NETCONN_SEM_PER_THREAD 408 #error LWIP_NETCONN_SEM_PER_THREAD==1 not supported 409 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 410 411 #endif /* !NO_SYS */ ``` 這些函數都是對操作系統的IPC通信機制進行簡單的封裝,在這里用戶只需要稍微注意一下sys\_arch\_sem\_wait()函數與sys\_arch\_mbox\_fetch()函數,因為LwIP中使用的時間是以毫秒(ms)為單位的,而操作系統中則以時鐘節拍(tick)為單位,那么在返回等待信號量或者郵箱所使用的時間就是要轉換成ms,而操作系統并未提供等待這些信息的時間,那么我們可以使用一個折中的方法,在獲取的時候開始記錄時間戳,在獲取結束后再次記錄一次時間戳,兩次時間戳相減就得到等待的時間,但是需要將這些時間(tick)轉換為毫秒,這種做法當然是不精確的,但是對LwIP來說影響不大。
                  <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>

                              哎呀哎呀视频在线观看