lwIP TCP/IP 協議棧筆記之四: 操作系統配置文件 sys_arch.c & sys_arch.h 詳解

目錄

1. 操作系統抽象層說明

1.1 Semaphores(信號量)

1.2 Mutexes(互斥鎖)

1.3 Mailboxes(郵箱)

1.4 Misc(雜項)

2. Time(時間)

3. Critical sections(關鍵代碼段/臨界區)


1. 操作系統抽象層說明

無需在NO_SYS模式下實現本節中的功能。 特定於操作系統的代碼應該在 arch/ sys_arch.h和sys_arch.c中實現。

操作系統仿真層在lwIP代碼和底層操作系統內核之間提供通用接口。 一般的想法是將lwIP移植到新架構只需要對少量頭文件和新的sys_arch實現進行小的更改。 也可以執行不依賴於任何底層操作系統的sys_arch實現。

sys_arch爲lwIP提供信號量,郵箱和互斥鎖。 對於完整的lwIP功能,可以在sys_arch中實現多線程支持,但基本的lwIP功能不需要這樣做。

除了提供sys_arch功能的源文件之外,OS仿真層還必須提供幾個頭文件,用於定義整個lwip中使用的宏。 所需的文件和它們必須定義的宏列在sys_arch描述下面。

從lwIP 1.4.0開始,信號量,互斥量和郵箱功能的原型都允許使用指針或實際的OS結構。 這樣,這些類型所需的內存可以就地分配(全局或堆棧)或堆(在“* _new()”函數內部分配)。

注意:

在sys_arch中使用mem_malloc()時要小心。 當malloc()引用mem_malloc()時,您可能遇到循環函數調用問題。在mem.c中,mem_init()嘗試使用mem_malloc分配信號量,當sys_arch使用mem_malloc時,當然無法執行該信號量。

相關聲明見 sys.h

1.1 Semaphores(信號量)

信號量可以是計數或二進制 - lwIP可用於兩種類型。 信號量由“sys_sem_t”類型表示,該類型在sys_arch.h文件中是typedef。郵箱等效地由“sys_mbox_t”類型表示。 互斥體由“sys_mutex_t”類型表示。 lwIP對內部表示這些類型的方式沒有任何限制。

/* 
    創建一個新的信號量。 
    信號量被分配給'sem'指向的內存(可以是指針或實際的OS結構)。
    “count”參數指定信號量的初始狀態(爲0或1)。
    如果已創建信號量,則應返回ERR_OK。 返回任何其他錯誤將提示出現了什麼問題,但除了斷言之外,沒有實現真正的錯誤處理。

    參數
        sem指向要創建的信號量的指針
        計算信號量的初始計數

    返回
        如果成功則爲ERR_OK,否則爲另一個錯誤
 */
err_t 	sys_sem_new (sys_sem_t *sem, u8_t count)

/*
    發送信號量

    參數
        sem 信號量發出信號
*/ 
void 	sys_sem_signal (sys_sem_t *sem)

/*
    在等待信號量發出信號的同時阻塞線程。 
    如果“timeout”參數不爲零,則只應在指定時間內阻塞線程(以毫秒爲單位)。 
    如果“timeout”參數爲零,則應阻塞線程,直到發出信號量信號。

    如果信號量未在指定時間內發出信號,則返回值爲SYS_ARCH_TIMEOUT;
    如果已發出信號(有或沒有等待),則返回值爲任何其他值。 
    請注意,lwIP實現了一個名爲sys_sem_wait()()的函數,該函數使用sys_arch_sem_wait()函數。

    參數
        sem信號量等待
        超時超時(以毫秒爲單位)等待(0 =永遠等待)

    返回
        超時時SYS_ARCH_TIMEOUT,成功時的任何其他值
*/ 
u32_t 	sys_arch_sem_wait (sys_sem_t *sem, u32_t timeout)

/*
    釋放信號量。

    參數
        sem信號量刪除
*/ 
void 	sys_sem_free (sys_sem_t *sem)

/*
    如果信號量有效則返回1,如果信號量無效則返回0。 
    使用指針時,一種簡單的方法是檢查 指針!= NULL。
*/ 
int 	sys_sem_valid (sys_sem_t *sem)

/*
    使信號量無效,以便sys_sem_valid()返回0.
    注意:這並不意味着信號量應該被釋放:在調用此函數之前總是調用sys_sem_free()
*/ 
void 	sys_sem_set_invalid (sys_sem_t *sem)

1.2 Mutexes(互斥鎖)

建議使用互斥鎖正確處理優先級倒置,尤其是在使用LWIP_CORE_LOCKING時。

互斥體由“sys_mutex_t”類型表示。 lwIP對內部表示這些類型的方式沒有任何限制。

/*
    創建一個新的互斥鎖。 
    請注意,lwIP代碼不會遞歸地使用互斥鎖,因此兩種實現類型(遞歸或非遞歸)都應該起作用。 
    互斥鎖被分配給'mutex'指向的內存(可以是指針或實際的OS結構)。 
    如果已創建互斥鎖,則應返回ERR_OK。 
    返回任何其他錯誤將提示出現了什麼問題,但除了斷言之外,沒有實現真正的錯誤處理。

    參數
        mutex 指向要創建的互斥鎖

    返回
        如果成功則爲ERR_OK,否則爲另一個錯誤
*/
err_t 	sys_mutex_new (sys_mutex_t *mutex)

/*
    阻止線程,直到可以抓住互斥鎖。

    參數
        mutex 鎖定的互斥鎖
*/ 
void 	sys_mutex_lock (sys_mutex_t *mutex)

/*
    釋放先前通過'sys_mutex_lock()'鎖定的互斥鎖。

    參數
        mutex 解鎖互斥鎖
*/ 
void 	sys_mutex_unlock (sys_mutex_t *mutex)

/*
    取消分配互斥鎖。

    參數
        要刪除的互斥鎖
*/ 
void 	sys_mutex_free (sys_mutex_t *mutex)

/* 
    有效性判斷:
    返回;1有效 0 無效
*/ 
int 	sys_mutex_valid (sys_mutex_t *mutex)

/*
    使互斥鎖無效,以便sys_mutex_valid()返回0。
    注意:這並不意味着應該釋放互斥鎖:在調用此函數之前總是調用sys_mutex_free()! 
*/ 
void 	sys_mutex_set_invalid (sys_mutex_t *mutex)

1.3 Mailboxes(郵箱)

郵箱應該實現爲允許發佈多個郵件的隊列。郵箱中的郵件只是一個指針,僅此而已。

郵箱等效地由“sys_mbox_t”類型表示。 lwIP對內部表示這些類型的方式沒有任何限制。

/*
    創建一個大小爲size的空郵箱
    存儲在郵箱中的元素是指針。 您必須在lwipopts.h中定義宏“_MBOX_SIZE”,或在實現中忽略此參數並使用默認大小。 如果已創建郵箱,則應返回ERR_OK。 返回任何其他錯誤將提示出現了什麼問題,但除了斷言之外,沒有實現真正的錯誤處理。

參數
     mbox指向要創建的mbox的指針
     此mbox中的大小(最小)消息數

返回
     如果成功則爲ERR_OK,否則爲其他錯誤
*/
err_t 	sys_mbox_new (sys_mbox_t *mbox, int size)

/*
    將消息發佈到mbox  (如果已滿,不會返回失敗)
    僅用於來自非ISR的任務

    參數
        mbox發佈消息
        msg 要發佈的消息(注意:可以爲NULL)
*/ 
void 	sys_mbox_post (sys_mbox_t *mbox, void *msg)

/*
    嘗試將郵件發佈到mbox  - (如果已滿,可能會失敗。)
    可以在ISR中使用(如果sys arch層允許這樣做)。一般情況不可以在ISR使用,僅任務使用
    如果已滿,則返回ERR_MEM,否則,如果發佈“msg”,則返回ERR_OK。

    參數
        郵箱發佈消息
        要發佈的消息(注意:可以爲NULL)
*/ 
err_t 	sys_mbox_trypost (sys_mbox_t *mbox, void *msg)

/*
    嘗試將郵件發佈到mbox  -( 如果已滿,可能會失敗。)
    ISR使用。 
    如果已滿,則返回ERR_MEM,否則,如果發佈“msg”,則返回ERR_OK。

    參數
        mbox mbox發佈消息
        要發佈的消息(注意:可以爲NULL)
*/ 
err_t 	sys_mbox_trypost_fromisr (sys_mbox_t *mbox, void *msg)

/*
    阻塞線程,直到消息到達郵箱,但不會阻塞線程超過“timeout”毫秒(類似於sys_arch_sem_wait()函數)。 
    如果“timeout”爲0,則應阻止該線程,直到消息到達。 
    “msg”參數是由函數設置的結果參數(即,通過執行“* msg = ptr”)。
    “msg”參數可能爲NULL,表示應刪除該消息。 
    返回值:超時返回SYS_ARCH_TIMEOUT如果有超時,如果收到消息,則返回任何其他值。

    請注意,具有類似名稱sys_mbox_fetch()的函數由lwIP實現。

    參數
        mbox從中獲取消息
        指針存儲消息的位置
        超時等待消息的最長時間(以毫秒爲單位)(0 =永遠等待)

返回
     超時時SYS_ARCH_TIMEOUT,如果收到消息則爲任何其他值
*/ 
u32_t 	sys_arch_mbox_fetch (sys_mbox_t *mbox, void **msg, u32_t timeout)

/*
    類似於sys_arch_mbox_fetch,但是如果郵箱中沒有郵件,它會立即返回代碼SYS_MBOX_EMPTY。 成功時返回0。
    爲了實現高效實現,可以將其定義爲sys_arch.h中的類似函數的宏,而不是普通函數。
    例如,一個簡單的實現可能是:#define sys_arch_mbox_tryfetch(mbox,msg)sys_arch_mbox_fetch(mbox,msg,1)雖然這會引入不必要的延遲。

    返回
        如果已收到消息,則爲0(毫秒);如果郵箱爲空,則爲SYS_MBOX_EMPTY
*/ 
u32_t 	sys_arch_mbox_tryfetch (sys_mbox_t *mbox, void **msg)

/*
    取消分配郵箱。
    如果在取消分配郵箱時郵箱中仍然存在郵件,則表明lwIP中存在編程錯誤,應通知開發人員。

    參數
        mbox要刪除
*/ 
void 	sys_mbox_free (sys_mbox_t *mbox)

/* Returns 1 if the mailbox is valid, 0 if it is not valid. 參考sem */ 
int 	sys_mbox_valid (sys_mbox_t *mbox)

/*
    使郵箱無效,以便sys_mbox_valid()返回0。
    注意:這並不意味着應該釋放郵箱:
    在調用此函數之前總是調用sys_mbox_free()!
*/ 
void 	sys_mbox_set_invalid (sys_mbox_t *mbox)
 

1.4 Misc(雜項)

/*
    睡眠指定的ms數

    睡一段時間。 睡覺時不處理超時。

    參數
        ms睡眠的毫秒數
*/
void 	sys_msleep (u32_t ms)

/*
    創建線程函數
    唯一的線程函數:啓動一個名爲“name”的新線程,優先級爲“prio”,它將在函數“thread()”中開始執行。 “arg”參數將作爲參數傳遞給thread()函數。 用於此線程的堆棧大小是“stacksize”參數。 返回新線程的id。 id和優先級都取決於系統。 
    注意:雖然這個函數返回一個值,但它絕不能失敗(端口必須斷言!)

    參數
        name       線程名稱(用於調試目的)
        thread     線程的線程函數
        arg        參數傳遞給'thread'
        stacksize  新線程的堆棧大小(以字節爲單位)(端口可能會被忽略)
        prio       新線程的優先級(可能被端口忽略)
*/ 
sys_thread_t 	sys_thread_new (const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
 
/*
    初始化sys_arch層。
    必須在其他任何事情之前調用sys_init()。 
 */
void 	sys_init (void)

2. Time(時間)

相關聲明見 sys.h

/*
    返回當前時間(以毫秒爲單位),可以與sys_jiffies相同或至少基於它。 這僅用於時間差異。
    不實現此功能意味着您不能使用某些模塊(例如,TCP時間戳,NO_SYS == 1的內部超時)。
    無論有無操作系統,爲了使用完整的協議棧,最好都實現
*/
u32_t 	sys_now (void)

3. Critical sections(關鍵代碼段/臨界區)

用於保護短代碼區域免受併發訪問。

相關聲明見 sys.h

  • 系統是裸機系統(可能帶有RTOS),並且可以控制中斷:將其實現爲LockInterrupts()/ UnlockInterrupts()
  • 系統使用具有來自工作線程的延遲中斷處理的RTOS:實現爲全局互斥鎖或鎖定/解鎖調度程序
  • 系統使用高級操作系統,例如 POSIX信號:實現爲全局互斥體
/* 
    根據opt.h 中可知,若希望在緩衝區分配,釋放和內存分配以及釋放期間對某些關鍵區域進行任務間保護,則    在lwipopts.h中定義SYS_LIGHTWEIGHT_PROT==1
*/

/*
    SYS_ARCH_DECL_PROTECT聲明一個保護變量。
    此宏將默認定義sys_prot_t類型的變量。
    如果特定端口需要不同的實現,則可以在sys_arch.h中定義此宏。
*/
#define 	SYS_ARCH_DECL_PROTECT(lev)   sys_prot_t lev


/*
    SYS_ARCH_PROTECT執行“快速”保護。 
    這可以通過禁用嵌入式系統的中斷或使用信號量或互斥量來實現。 
    該實現應允許在已受保護時調用SYS_ARCH_PROTECT。 
    舊保護級別在變量“lev”中返回。 
    此宏將默認調用sys_arch_protect()函數,該函數應在sys_arch.c中實現。 
    如果特定端口需要不同的實現,則可以在sys_arch.h中定義此宏
*/ 
#define 	SYS_ARCH_PROTECT(lev)   lev = sys_arch_protect()

/* 
    SYS_ARCH_UNPROTECT執行“快速”保護級別設置爲“lev”。
    這可以通過在MACRO中將中斷級別設置爲“lev”或使用信號量或互斥量來實現。 
    該宏將默認調用sys_arch_unprotect()函數,該函數應在sys_arch.c中實現。 
    如果特定端口需要不同的實現,則可以在sys_arch.h中定義此宏
*/ 
#define 	SYS_ARCH_UNPROTECT(lev)   sys_arch_unprotect(lev)
 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章