源码文件:RT-Thread Nano V3.1.3\include\rtservice.h (源文件修改日期:2017-11-15)
RT-Thread官网:https://www.rt-thread.org/
RT-Thread内核采用面向对象的设计思想进行设计,系统级的基础设施都是一种内核对象,例如线程,信号量,互斥量,定时器等。
对象容器中包含了每类内核对象的信息,包括对象类型,大小等。
对象容器给每类内核对象分配了一个链表,所有的内核对象都被链接到该链表上。
如图 RT-Thread 的内核对象容器及链表如下图所示:
由此可见,学习内核源码前,需要了解链表的构造及实现函数。
RT-Thread Nano V3.1.3\include\rtservice.h中包含单链表和双链表,RT-Thread主要使用双链表结构,作为RT-Thread源码分析第1篇文章,首先学习双链表。
关于单链表内容,请参考作者另一篇文章:RT-Thread源码分析2:单链表
RT-Thread双链表实际上是循环双向链表,每个节点有两个指针成员next
和prev
;
next
指向下一个节点,prev
指向上一个节点,链表头不是链表成员,作为链表处理函数的入口;
/**
* Double List structure
*/
struct rt_list_node
{
struct rt_list_node *next; /**< point to next node. */
struct rt_list_node *prev; /**< point to prev node. */
};
typedef struct rt_list_node rt_list_t; /**< Type for lists. */
函数定义中用到的宏定义说明
rt_inline,定义如下,static 关键字的作用是令函数只能在当前的文件中使用;inline 表示内联,用 static 修饰后在调用函数时会建议编译器进行内联展开。#define rt_inline static __inline
注:RT-Thread Nano内核未调用
/**
* @brief initialize a list object
*/
#define RT_LIST_OBJECT_INIT(object) { &(object), &(object) }
/**
* @brief initialize a list
*
* @param l list to be initialized
*/
rt_inline void rt_list_init(rt_list_t *l)
{
l->next = l->prev = l;
}
在双链表头后面插入一个节点
/**
* @brief insert a node after a list
*
* @param l list to insert it
* @param n new node to be inserted
*/
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;
}
在双链表头前面插入一个节点
/**
* @brief insert a node before a list
*
* @param n new node to be inserted
* @param l list to insert it
*/
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;
}
/**
* @brief remove node from list.
* @param n the node to remove from the list.
*/
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;
}
/**
* @brief tests whether a list is empty
* @param l the list to test.
*/
rt_inline int rt_list_isempty(const rt_list_t *l)
{
return l->next == l;
}
说明:如果链表头的指针next
指向自身,说明链表为空。
/**
* @brief get the list length
* @param l the list to get.
*/
rt_inline unsigned int rt_list_len(const rt_list_t *l)
{
unsigned int len = 0;
const rt_list_t *p = l;
while (p->next != l)
{
p = p->next;
len ++;
}
return len;
}
根据成员变量(链表节点成员)地址,获取当前所在结构体的地址
/**
* @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)
参数node
:指向链表节点(属于结构体成员)的指针变量
参数type
:结构体类型
参数member
:链表节点在结构体中的成员名
返回值:指向当前结构体的指针
/**
* 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)))
此函数来源于Linux内核源码
从一个结构的成员指针找到其容器的指针。
#define list_entry(ptr, type, member) / ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
分析rt_container_of(ptr, type, member),举例结构体定义为:
typedef struct xxx
{
......; //结构体中的其他成员变量
type_m member;
......; //结构体中的其他成员变量
}type;
/* 定义变量 */
type a;
type *p;
type_m *ptr;
ptr = &(a.member);
p = rt_container_of(ptr, type, member);
/* 结果:p指向a,得到a的地址 */
((type *)0)把“0”强制转化为指针类型,指向type类型的数据;
&((type *)0)->member因为指针是type *
类型的,所以可以取到以“0”为基地址的type型变量成员member的地址,也就是偏移地址;也就等于成员member到结构体基地址的偏移字节数。(注:内存单元按字节编址)
(unsigned long)(&((type *)0)->member)把偏移地址强制转化为unsigned long
型数据;
(char *)(ptr)ptr为只指向type_m
类型的指针(指向member成员的真实地址,使用(char *)
强制转化为指向char
型的指针;这样ptr指针的加减操作步长为一个字节。
((char *)(ptr) - (unsigned long)(&((type *)0)->member))member成员的真实地址 减去 偏移地址,得到结构体真实地址,此时地址指向的数据类型为char
型。
(type *)强制类型转化为结构体指针类型,最终返回指向结构体的真实地址。
注:RT-Thread Nano V3.1.3\components\finsh\cmd.c long list_mempool(void)
调用一次
/**
* rt_list_for_each - iterate over a list
* @pos: the rt_list_t * to use as a loop cursor.
* @head: the head for your list.
*/
#define rt_list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
pos
指向宿主结构的指针,在for循环中是一个迭代变量
head
链表头
注:RT-Thread Nano内核未调用
/**
* rt_list_for_each_safe - iterate over a list safe against removal of list entry
* @pos: the rt_list_t * to use as a loop cursor.
* @n: another rt_list_t * to use as temporary storage
* @head: the head for your list.
*/
#define rt_list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
pos
指向宿主结构的指针,在for循环中是一个迭代变量
n
用于临时存储下一个数据结构的指针变量
head
链表头
注:RT-Thread Nano内核未调用
/**
* rt_list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define rt_list_for_each_entry(pos, head, member) \
for (pos = rt_list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = rt_list_entry(pos->member.next, typeof(*pos), member))
pos
指向宿主结构的指针,在for循环中是一个迭代变量
head
链表头
member
结构体中链表的成员名
注:RT-Thread Nano内核未调用
/**
* rt_list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define rt_list_for_each_entry_safe(pos, n, head, member) \
for (pos = rt_list_entry((head)->next, typeof(*pos), member), \
n = rt_list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = rt_list_entry(n->member.next, typeof(*n), member))
注:RT-Thread Nano内核未调用
/**
* rt_list_first_entry - get the first element from a list
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*
* Note, that list is expected to be not empty.
*/
#define rt_list_first_entry(ptr, type, member) \
rt_list_entry((ptr)->next, type, member)
微信公众号:萤火虫的电子笔记
分享电子产品开发软、硬件方面知识,51单片机、STM32、ARM、AltiumDesigner PCB设计、开发平台、软件工具等知识分享。
欢迎转发,请注明出处及作者。关注微信公众号,获取最新文章动态。