目錄
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)