rt_container_of 已知一個結構體裡面的成員的地址,反推出該結構體的首地址
阿新 • • 發佈:2020-10-12
/** * rt_container_of - return the member address of ptr, if the type of ptr is the * struct type. */ #define rt_container_of(ptr, type, member) \ ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member))) /** * @brief get the struct for this entry * @param node the entry point 表示一個節點的地址 * @param type the type of structure 該節點所在的結構體的型別 * @param member the name of list in structure 該節點在該結構體中的成員名稱*/ #define rt_list_entry(node, type, member) \ rt_container_of(node, type, member)
具體實現演算法:
我們知道了一個節點 tlist 的地址 ptr,現在要推算出該節點所在的 type 型別的結構體的起始地址 f_struct_ptr。我們可以將 ptr的值減去圖中灰色部分的偏移的大小就可以得到 f_struct_ptr 的地址,現在的關鍵是如何計算出灰色部分的偏移大小。這裡採取的做法是將 0 地址強制型別型別轉換為 type,即(type *)0,然後通過指標訪問結構體成員的方式獲取到偏移的大小,即(&((type *)0)->member),最後即可算出 f_struct_ptr = ptr -(&((type *)0)->member)。
用法舉例:
/* 啟動系統排程器 */ void rt_system_scheduler_start(void) { register struct rt_thread *to_thread; /* 手動指定第一個執行的執行緒 */ (1) to_thread = rt_list_entry(rt_thread_priority_table[0].next,struct rt_thread,tlist); rt_current_thread = to_thread; (2)//將獲取到的第一個要執行的執行緒控制塊指標傳到全域性變數rt_current_thread 中 /* 切換到第一個執行緒,該函式在 context_rvds.S 中實現, 在 rthw.h 宣告,用於實現第一次執行緒切換。 當一個彙編函式在 C 檔案中呼叫的時候,如果有形參, 則執行的時候會將形參傳人到 CPU 暫存器 r0。*/ rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp); (3) }
這裡只關心rt_list_entry的用法,rt_thread的結構體定義如下(簡化了的)。要獲取一個rt_thread,則根據連結串列通過rt_list_entry獲得對應的執行緒。
struct rt_thread { void *sp; /* 執行緒棧指標 */ void *entry; /* 執行緒入口地址 */ void *parameter; /* 執行緒形參 */ void *stack_addr; /* 執行緒棧起始地址 */ rt_uint32_t stack_size; /* 執行緒棧大小,單位為位元組 */ rt_list_t tlist; /* 執行緒連結串列節點 */ (1) };