文章目錄
1、RT-Thread 軟件架構
2、RT-Thread 內核結構
3、 預備知識
3.1鏈表
鏈表是通過節點把離散的數據鏈接成一個表,通過對節點的插入和刪除操作從而實現對數據的存取。而數組是通過開闢一段連續的內存來存儲數據,這是數組和鏈表最大的區別。數組的每個成員對應鏈表的節點,成員和節點的數據類型可以是標準的C類型或者是用戶自定義的結構體。數組有起始地址和結束地址,而鏈表是一個圈,沒有頭和尾之分,但是爲了方便節點的插入和刪除操作會人爲的規定一個根節點。
單向鏈表:
雙向鏈表:
3.2 節點
3.2.2 節點初始化
rt_inline void rt_list_init(rt_list_t *l)
{
l->next = l->prev = l;
}
3.2.3 在雙向鏈表表頭後面插入一個節點
rt_inline void rt_list_insert_after(rt_list_t *l, rt_list_t *n)
{
l->next->prev = n;
n->next = l->next;
l->next = n;
n->prev = l;
}
3.2.4 在雙向鏈表表頭前面插入一個節點
rt_inline void rt_list_insert_before(rt_list_t *l, rt_list_t *n)
{
l->prev->next = n;
n->prev = l->prev;
l->prev = n;
n->next = l;
}
3.2.5 從雙向鏈表刪除一個節點
rt_inline void rt_list_remove(rt_list_t *n)
{
n->next->prev = n->prev;
n->prev->next = n->next;
n->next = n->prev = n;
}
3.2.6 從節點中獲取所在結構體的首地址
#define rt_list_entry(node, type, member) \
rt_container_of(node, type, member)
#define rt_list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
node 表示一個節點的地址, type 表示該節點所在的結構體的類型,
member 表示該節點在該結構體中的成員名稱。
rt_container_of()的實現算法具體見圖:
我們知道了一個節點 tlist 的地址 ptr,現在要推算出該節點所在的 type 類型的結構體的起始地址 f_struct_ptr。我們可以將 ptr 的值減去圖中灰色部分的偏移的大小就可以得到 f_struct_ptr 的地址,現在的關鍵是如何計算出灰色部分的偏移大小。這裏採取的做法是將 0 地址強制類型類型轉換爲 type,即(type *)0,然後通過指針訪問結構體成員的方式獲取到偏移的大小,即(&((type *)0)->member), 最後即可算出 f_struct_ptr = ptr -(&((type *)0)->member)。
3.3 面向對象編程思想
3.3.1 封裝
3.3.2 繼承
3.3.3 多態
4 內核對象管理架構
RT-Thread 採用內核對象管理系統來訪問 / 管理所有內核對象,內核對象包含了內核中線程,信號量,互斥量,事件,郵箱,消息隊列和定時器,內存池,設備驅動等。對象容器中包含了每類內核對象的信息,包括對象類型,大小等。對象容器給每類內核對象分配了一個鏈表,所有的內核對象都被鏈接到該鏈表上,如圖 RT-Thread 的內核對象容器及鏈表如下圖所示:
下圖則顯示了 RT-Thread 中各類內核對象的派生和繼承關係:
4.1 內核對象數據結構
4.1.1 對象結構
4.1.2 對象容器結構
4.1.3 初始化對象容器
容 器 是 一 個 全 部 變 量 的 數 組 , 數 據 類 型 爲 struct rt_object_information, 這是一個結構體類型, 包含對象的三個信息,分別爲對象類型、對象列表節點頭和對象的大小。
static struct rt_object_information rt_object_container[RT_Object_Info_Unknown] =
{
/* initialize object container - thread */
{RT_Object_Class_Thread, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Thread), sizeof(struct rt_thread)},
#ifdef RT_USING_SEMAPHORE
/* initialize object container - semaphore */
{RT_Object_Class_Semaphore, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Semaphore), sizeof(struct rt_semaphore)},
#endif
#ifdef RT_USING_MUTEX
/* initialize object container - mutex */
{RT_Object_Class_Mutex, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Mutex), sizeof(struct rt_mutex)},
#endif
#ifdef RT_USING_EVENT
/* initialize object container - event */
{RT_Object_Class_Event, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Event), sizeof(struct rt_event)},
#endif
#ifdef RT_USING_MAILBOX
/* initialize object container - mailbox */
{RT_Object_Class_MailBox, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MailBox), sizeof(struct rt_mailbox)},
#endif
#ifdef RT_USING_MESSAGEQUEUE
/* initialize object container - message queue */
{RT_Object_Class_MessageQueue, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MessageQueue), sizeof(struct rt_messagequeue)},
#endif
#ifdef RT_USING_MEMHEAP
/* initialize object container - memory heap */
{RT_Object_Class_MemHeap, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemHeap), sizeof(struct rt_memheap)},
#endif
#ifdef RT_USING_MEMPOOL
/* initialize object container - memory pool */
{RT_Object_Class_MemPool, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemPool), sizeof(struct rt_mempool)},
#endif
#ifdef RT_USING_DEVICE
/* initialize object container - device */
{RT_Object_Class_Device, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Device), sizeof(struct rt_device)},
#endif
/* initialize object container - timer */
{RT_Object_Class_Timer, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Timer), sizeof(struct rt_timer)},
#ifdef RT_USING_MODULE
/* initialize object container - module */
{RT_Object_Class_Module, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Module), sizeof(struct rt_dlmodule)},
#endif
};
_OBJ_CONTAINER_LIST_INIT()是一個帶參宏,用於初始化一個
節點 list,在 object.c 中定義
#define _OBJ_CONTAINER_LIST_INIT(c) \
{&(rt_object_container[c].object_list), &(rt_object_container[c].object_list)}
4.1.4 從容器中獲取指定類型的對象信息
struct rt_object_information *
rt_object_get_information(enum rt_object_class_type type)
{
int index;
for (index = 0; index < RT_Object_Info_Unknown; index ++)
if (rt_object_container[index].type == type) return &rt_object_container[index];
return RT_NULL;
}
4.1.5 初始化對象
每創建一個對象,都需要先將其初始化,主要分成兩個部分的工作,首先將對象控制塊裏面與對象相關的成員初始化,然後將該對象插入到對象容器中。
/**
* This function will initialize an object and add it to object system
* management.
*
* @param object the specified object to be initialized.
* @param type the object type.
* @param name the object name. In system, the object's name must be unique.
*/
void rt_object_init(struct rt_object *object,
enum rt_object_class_type type,
const char *name)
{
register rt_base_t temp;
struct rt_list_node *node = RT_NULL;
struct rt_object_information *information;
#ifdef RT_USING_MODULE
struct rt_dlmodule *module = dlmodule_self();
#endif
/* get object information */
information = rt_object_get_information(type);
RT_ASSERT(information != RT_NULL);
/* check object type to avoid re-initialization */
/* enter critical */
rt_enter_critical();
/* try to find object */
for (node = information->object_list.next;
node != &(information->object_list);
node = node->next)
{
struct rt_object *obj;
obj = rt_list_entry(node, struct rt_object, list);
if (obj) /* skip warning when disable debug */
{
RT_ASSERT(obj != object);
}
}
/* leave critical */
rt_exit_critical();
/* initialize object's parameters */
/* set object type to static */
object->type = type | RT_Object_Class_Static;
/* copy name */
rt_strncpy(object->name, name, RT_NAME_MAX);
RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));
/* lock interrupt */
temp = rt_hw_interrupt_disable();
#ifdef RT_USING_MODULE
if (module)
{
rt_list_insert_after(&(module->object_list), &(object->list));
object->module_id = (void *)module;
}
else
#endif
{
/* insert object into information object list */
rt_list_insert_after(&(information->object_list), &(object->list));
}
/* unlock interrupt */
rt_hw_interrupt_enable(temp);
}
4.1.6 線程結構
線程狀態切換:
RT-Thread 中,實際上線程並不存在運行狀態,就緒狀態和運行狀態是等同的。
4.1.7 初始化線程
在線程初始化之後,線程通過自身的 list 節點將自身掛到容器的對象列表中,對象初始化函數在線程初始化函數裏面被調用。
rt_err_t rt_thread_init(struct rt_thread *thread,
const char *name,
void (*entry)(void *parameter),
void *parameter,
void *stack_start,
rt_uint32_t stack_size,
rt_uint8_t priority,
rt_uint32_t tick)
{
/* thread check */
RT_ASSERT(thread != RT_NULL);
RT_ASSERT(stack_start != RT_NULL);
/* initialize thread object */
rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);
return _rt_thread_init(thread,
name,
entry,
parameter,
stack_start,
stack_size,
priority,
tick);
}
4.1.8 初始化線程棧
在動態創建線程和初始化線程的時候,會使用到內部的線程初始化函數_rt_thread_init(),_rt_thread_init() 函數會調用棧初始化函數 rt_hw_stack_init(),在棧初始化函數裏會手動構造一個上下文內容,這個上下文內容將被作爲每個線程第一次執行的初始值。上下文在棧裏的排布如下圖所示:
rt_uint8_t *rt_hw_stack_init(void *tentry,
void *parameter,
rt_uint8_t *stack_addr,
void *texit)
{
struct stack_frame *stack_frame;
rt_uint8_t *stk;
unsigned long i;
/* 對傳入的棧指針做對齊處理 */
stk = stack_addr + sizeof(rt_uint32_t);
stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
stk -= sizeof(struct stack_frame);
/* 得到上下文的棧幀的指針 */
stack_frame = (struct stack_frame *)stk;
/* 把所有寄存器的默認值設置爲 0xdeadbeef */
for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
{
((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
}
/* 根據 ARM APCS 調用標準,將第一個參數保存在 r0 寄存器 */
stack_frame->exception_stack_frame.r0 = (unsigned long)parameter;
/* 將剩下的參數寄存器都設置爲 0 */
stack_frame->exception_stack_frame.r1 = 0; /* r1 寄存器 */
stack_frame->exception_stack_frame.r2 = 0; /* r2 寄存器 */
stack_frame->exception_stack_frame.r3 = 0; /* r3 寄存器 */
/* 將 IP(Intra-Procedure-call scratch register.) 設置爲 0 */
stack_frame->exception_stack_frame.r12 = 0; /* r12 寄存器 */
/* 將線程退出函數的地址保存在 lr 寄存器 */
stack_frame->exception_stack_frame.lr = (unsigned long)texit;
/* 將線程入口函數的地址保存在 pc 寄存器 */
stack_frame->exception_stack_frame.pc = (unsigned long)tentry;
/* 設置 psr 的值爲 0x01000000L,表示默認切換過去是 Thumb 模式 */
stack_frame->exception_stack_frame.psr = 0x01000000L;
/* 返回當前線程的棧地址 */
return stk;
}
擴展閱讀:
RT-Thread代碼啓動過程與線程切換的實現
RT-Thread學習筆記之設備框架
RT-Thread學習筆記之FinSH組件
RT-Thread學習筆記之網絡框架