目录
1.3、rt_object_class_type枚举类型(对象类型)
1.3.1、RT_Object_Class_Static作用
2.1.1、RT_Object_Info_Unknown作用
2.2、rt_object_information结构体(对象信息)
2.3.2、_OBJ_CONTAINER_LIST_INIT宏
3.5、rt_object_is_systemobject()函数
3.7、rt_object_get_information()函数
3.10、rt_object_get_pointers()函数
4.2.3、rt_ipc_list_resume_all()函数
1、对象
RT-Thread 内核采用面向对象的设计思想进行设计,系统级的基础设施都是一种内核对象,例如线程,信号量,互斥量,定时器等。
1.1、继承关系
从面向对象的观点,可以认为每一种具体对象是抽象对象的派生,继承了基本对象的属性并在此基础上扩展了与自己相关的属性。
1.2、静态对象和动态对象
内核对象分为两类:静态内核对象和动态内核对象。静态对象会占用 RAM 空间,不依赖于内存堆管理器,内存分配时间确定。动态对象则依赖于内存堆管理器,运行时申请 RAM 空间,当对象被删除后,占用的 RAM 空间被释放。
静态对象 | 标识对象是静态的(存放在数据段)。 |
动态对象 | 标识对象是从堆中分配的,不需要时需要释放! |
1.3、rt_object_class_type枚举类型(对象类型)
enum rt_object_class_type
{
RT_Object_Class_Null = 0, /* 未使用 */
RT_Object_Class_Thread, /* 线程 */
RT_Object_Class_Semaphore, /* 信号量*/
RT_Object_Class_Mutex, /* 互斥量 */
RT_Object_Class_Event, /* 事件 */
RT_Object_Class_MailBox, /* 邮箱 */
RT_Object_Class_MessageQueue, /* 消息队列 */
RT_Object_Class_MemHeap, /* 内存堆 */
RT_Object_Class_MemPool, /* 内存池 */
RT_Object_Class_Device, /* 设备 */
RT_Object_Class_Timer, /* 定时器 */
RT_Object_Class_Module, /* 模块 */
RT_Object_Class_Unknown, /* 未知 */
RT_Object_Class_Static = 0x80 /* 静态对象 */
};
1.3.1、RT_Object_Class_Static作用
RT_Object_Class_Static 用于标识对象是静态对象。
注:如果是静态对象,那么对象类型的最高位将是1(是RT_Object_Class_Static 与其他对象类型的与操作),否则就是动态对象,系统最多能够容纳的对象类别数目是 127 个。
1.4、rt_object结构体(对象结构体)
rt_object是内核对象的基础结构体,所有的对象均使用到此结构体。
//对象结构体
struct rt_object
{
char name[RT_NAME_MAX]; /* 对象名字 */
rt_uint8_t type; /* 对象类型 */
rt_uint8_t flag; /* 对象标志 */
rt_list_t list; /* 对象链表 */
};
typedef struct rt_object *rt_object_t; /* 类型定义rt_object_t */
信号量、互斥量、事件、邮箱、消息队列、内存堆、内存池、设备、定时器的结构体中均有parent成员(类型为struct rt_object)。
线程对象的结构体中虽然没有类型为struct rt_ipc_object的成员。但其结构体的前面部分,其成员类型与struct rt_ipc_object的成员类型完全一致!
struct rt_thread
{
char name[RT_NAME_MAX];
rt_uint8_t type;
rt_uint8_t flags;
rt_list_t list;
...
}
1.4.1、对象flags说明
flags根据对象的不同而意义不同!
内核对象 | 标志 | 说明 |
信号量、互斥量、事件集、邮箱、消息队列 | RT_IPC_FLAG_FIFO | 采用先进先出策略 |
RT_IPC_FLAG_PRIO | 采用优先级策略 | |
定时器 | RT_TIMER_FLAG_ONE_SHOT | 单次定时 |
RT_TIMER_FLAG_PERIODIC | 周期定时 | |
RT_TIMER_FLAG_ACTIVATED | 定时器激活 | |
RT_TIMER_FLAG_DEACTIVATED | 定时器未激活 |
2、对象容器
2.1、rt_object_info_type枚举
enum rt_object_info_type
{
RT_Object_Info_Thread = 0, /**< The object is a thread. */
#ifdef RT_USING_SEMAPHORE
RT_Object_Info_Semaphore, /**< The object is a semaphore. */
#endif
#ifdef RT_USING_MUTEX
RT_Object_Info_Mutex, /**< The object is a mutex. */
#endif
#ifdef RT_USING_EVENT
RT_Object_Info_Event, /**< The object is a event. */
#endif
#ifdef RT_USING_MAILBOX
RT_Object_Info_MailBox, /**< The object is a mail box. */
#endif
#ifdef RT_USING_MESSAGEQUEUE
RT_Object_Info_MessageQueue, /**< The object is a message queue. */
#endif
#ifdef RT_USING_MEMHEAP
RT_Object_Info_MemHeap, /**< The object is a memory heap */
#endif
#ifdef RT_USING_MEMPOOL
RT_Object_Info_MemPool, /**< The object is a memory pool. */
#endif
#ifdef RT_USING_DEVICE
RT_Object_Info_Device, /**< The object is a device */
#endif
RT_Object_Info_Timer, /**< The object is a timer. */
RT_Object_Info_Unknown, /**< The object is unknown. */
}
2.1.1、RT_Object_Info_Unknown作用
用于灵活定义对象容器的大小。
static struct rt_object_information rt_object_container[RT_Object_Info_Unknown]
2.2、rt_object_information结构体(对象信息)
struct rt_object_information
{
enum rt_object_class_type type; /* 对象类型 */
rt_list_t object_list; /* 对象链表 */
rt_size_t object_size; /* 对象类型大小 */
};
一类对象由一个 rt_object_information 结构体来管理。每一个这类对象的具体实例都通过链表节点object_list的形式挂接在相应的对象链表上(例如线程对象挂到线程链表上、信号量对象挂到信号量链表上等)。而这一类对象的内存块尺寸由 object_size 标识出来(每一类对象的具体实例,他们占有的内存块大小都是相同的)。
2.3、rt_object_container结构体
Rt-Thread的对象都是通过对象容器进行管理。
static struct rt_object_information rt_object_container[RT_Object_Info_Unknown] =
{
//初始化线程对象容器
{RT_Object_Class_Thread, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Thread), sizeof(struct rt_thread)},
#ifdef RT_USING_SEMAPHORE
//初始化信号量对象容器
{RT_Object_Class_Semaphore, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Semaphore), sizeof(struct rt_semaphore)},
#endif
#ifdef RT_USING_MUTEX
//初始化互斥量对象容器
{RT_Object_Class_Mutex, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Mutex), sizeof(struct rt_mutex)},
#endif
#ifdef RT_USING_EVENT
//初始化事件对象容器
{RT_Object_Class_Event, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Event), sizeof(struct rt_event)},
#endif
#ifdef RT_USING_MAILBOX
//初始化邮箱对象容器
{RT_Object_Class_MailBox, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MailBox), sizeof(struct rt_mailbox)},
#endif
#ifdef RT_USING_MESSAGEQUEUE
//初始化消息队列对象容器
{RT_Object_Class_MessageQueue, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MessageQueue), sizeof(struct rt_messagequeue)},
#endif
#ifdef RT_USING_MEMHEAP
//初始化内存堆对象容器
{RT_Object_Class_MemHeap, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemHeap), sizeof(struct rt_memheap)},
#endif
#ifdef RT_USING_MEMPOOL
//初始化内存池对象容器
{RT_Object_Class_MemPool, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemPool), sizeof(struct rt_mempool)},
#endif
#ifdef RT_USING_DEVICE
//初始化设备对象容器
{RT_Object_Class_Device, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Device), sizeof(struct rt_device)},
#endif
//初始化定时器对象容器
{RT_Object_Class_Timer, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Timer), sizeof(struct rt_timer)},
#ifdef RT_USING_MODULE
//初始化模块对象容器
{RT_Object_Class_Module, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Module), sizeof(struct rt_dlmodule)},
#endif
};
2.3.1、RT_USING_XXX宏
RT-thread是可裁剪的。定义相应宏开启相应功能。
宏 | 说明 |
RT_USING_SEMAPHORE | 使用信号量 |
RT_USING_MUTEX | 使用互斥量 |
RT_USING_EVENT | 使用事件 |
RT_USING_MAILBOX | 使用邮箱 |
RT_USING_MESSAGEQUEUE | 使用队列 |
RT_USING_MEMHEAP | 使用内存堆 |
RT_USING_MEMPOOL | 使用内存池 |
RT_USING_DEVICE | 使用设备 |
RT_USING_MODULE | 使用模块 |
2.3.2、_OBJ_CONTAINER_LIST_INIT宏
_OBJ_CONTAINER_LIST_INIT宏的作用是初始化对象容器的object_list成员链表(将object_list的prev成员和next成员设置为object_list的地址)。
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. */
struct rt_object_information
{
enum rt_object_class_type type; /**< object class type */
rt_list_t object_list; /**< object list */
rt_size_t object_size; /**< object size */
};
#define _OBJ_CONTAINER_LIST_INIT(c) \
{&(rt_object_container[c].object_list), &(rt_object_container[c].object_list)}
3、函数
3.1、rt_object_init()函数
此函数将初始化一个对象并将其添加到对象容器中。
1)设置object的类型(并标识静态类型)和object的名称
2)调用钩子回调
3)将object插入到类型为type的对象链表中。
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;
information = rt_object_get_information(type); //获取对象信息
RT_ASSERT(information != RT_NULL); //断言information != RT_NULL
rt_enter_critical(); //进入临界区
//寻找对象,仅用于断言此对象未在对象容器中
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); //获取对象
RT_ASSERT(obj != object); //断言obj != object
}
rt_exit_critical(); //离开临界区
//初始化对象参数,并设置对象类型为静态类型
object->type = type | RT_Object_Class_Static;
rt_strncpy(object->name, name, RT_NAME_MAX); //设置名字
RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object)); //调用回调
temp = rt_hw_interrupt_disable(); //关中断
{
rt_list_insert_after(&(information->object_list), &(object->list)); // 将对象插入对象信息链表
}
rt_hw_interrupt_enable(temp); //开中断
}
3.2、rt_object_allocate()函数
此函数功能与rt_object_init()函数差不多,都是初始化一个对象并将其添加到对象容器中。不过rt_object_init()函数初始化的对象是静态的。rt_object_allocate()函数初始化的对象是动态的。
1)分配object内存,并初始化
2)设置object的类型和object的名称
3)调用钩子回调
4)将object插入到类型为type的对象链表中。
rt_object_t rt_object_allocate(enum rt_object_class_type type, const char *name)
{
struct rt_object *object;
register rt_base_t temp;
struct rt_object_information *information;
RT_DEBUG_NOT_IN_INTERRUPT; //断言该函数不在ISR中调用
information = rt_object_get_information(type); //获取对象信息
RT_ASSERT(information != RT_NULL); //断言information != RT_NULL
object = (struct rt_object *)RT_KERNEL_MALLOC(information->object_size); //分配内存
if (object == RT_NULL) //从分配内存失败
{
return RT_NULL; //返回RT_NULL
}
rt_memset(object, 0x0, information->object_size); //清0
object->type = type; //设置对象类型
object->flag = 0; //设置对象标志为0
rt_strncpy(object->name, name, RT_NAME_MAX); //设置对象名字
RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object)); //调用回调
temp = rt_hw_interrupt_disable(); //关中断
{
rt_list_insert_after(&(information->object_list), &(object->list)); //将对象插入到对象信息链表
}
rt_hw_interrupt_enable(temp); //关中断
return object; //返回对象
}
3.3、rt_object_detach()函数
此函数将从对象容器中脱离一个静态对象。
1)调用钩子函数
2)从相应对象链表中移除此对象
void rt_object_detach(rt_object_t object)
{
register rt_base_t temp;
RT_ASSERT(object != RT_NULL); //断言object != RT_NULL
RT_OBJECT_HOOK_CALL(rt_object_detach_hook, (object)); //调用回调
object->type = 0; //复位对象类型
temp = rt_hw_interrupt_disable(); //关中断
rt_list_remove(&(object->list)); //从对象信息链表中移除
rt_hw_interrupt_enable(temp); //开中断
}
3.4、rt_object_delete()函数
此函数将删除一个动态对象并释放对象内存。
1)调用钩子函数
2)从相应对象链表中移除此对象
3)释放对象内存
void rt_object_delete(rt_object_t object)
{
register rt_base_t temp;
RT_ASSERT(object != RT_NULL); //断言object != RT_NULL
RT_ASSERT(!(object->type & RT_Object_Class_Static)); //断言对象不是静态对象
RT_OBJECT_HOOK_CALL(rt_object_detach_hook, (object)); //调用回调
object->type = 0; //复位对象类型
temp = rt_hw_interrupt_disable(); //关中断
rt_list_remove(&(object->list)); //从对象信息链表中移除
rt_hw_interrupt_enable(temp); //开中断
RT_KERNEL_FREE(object); //释放对象内存
}
3.5、rt_object_is_systemobject()函数
判断对象是否是静态对象(根据对象类型是否与上RT_Object_Class_Static判断)。
rt_bool_t rt_object_is_systemobject(rt_object_t object)
{
RT_ASSERT(object != RT_NULL); //断言object != RT_NULL
if (object->type & RT_Object_Class_Static) //判断是否是静态对象
return RT_TRUE; //返回RT_TRUE
return RT_FALSE; //返回RT_FALSE
}
3.6、rt_object_get_type()函数
此函数用于获取对象类型。
rt_uint8_t rt_object_get_type(rt_object_t object)
{
RT_ASSERT(object != RT_NULL); //断言object != RT_NULL
return object->type & ~RT_Object_Class_Static; //返回对象类型
}
3.7、rt_object_get_information()函数
此函数用于根据对象类型获取对象信息。
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; //返回RT_NULL
}
3.8、rt_object_find()函数
此函数用于查找指定名称的对象。
1)根据对象类型获取对象信息。
2)遍历对象链表,并比较名称
rt_object_t rt_object_find(const char *name, rt_uint8_t type)
{
struct rt_object *object = RT_NULL;
struct rt_list_node *node = RT_NULL;
struct rt_object_information *information = RT_NULL;
/* 参数检查 */
if ((name == RT_NULL) || (type > RT_Object_Class_Unknown))
return RT_NULL; //返回RT_NULL
RT_DEBUG_NOT_IN_INTERRUPT; //断言不在ISR中调用
rt_enter_critical(); //进入临界区
if (information == RT_NULL) //信息对象为空
{
information = rt_object_get_information((enum rt_object_class_type)type); //查找对象信息
RT_ASSERT(information != RT_NULL); //断言information != RT_NULL
}
/* 从信息对象链表中遍历 */
for (node = information->object_list.next;
node != &(information->object_list);
node = node->next)
{
object = rt_list_entry(node, struct rt_object, list); //获取对象
if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0) //通过比对名字查找
{
rt_exit_critical(); //离开临界区
return object; //返回对象
}
}
rt_exit_critical(); //离开临界区
return RT_NULL; //返回RT_NULL
}
3.9、rt_object_get_length()函数
此函数用于获取指定类型对象的数量。
int rt_object_get_length(enum rt_object_class_type type)
{
int count = 0;
rt_ubase_t level;
struct rt_list_node *node = RT_NULL;
struct rt_object_information *information = RT_NULL;
information = rt_object_get_information((enum rt_object_class_type)type);
if (information == RT_NULL) return 0;
level = rt_hw_interrupt_disable(); //关中断
/* 获取对象的数量 */
rt_list_for_each(node, &(information->object_list))
{
count ++;
}
rt_hw_interrupt_enable(level); //开中断
return count;
}
3.10、rt_object_get_pointers()函数
此函数将复制指定类型的对象指针,其最大长度由maxlen指定。
int rt_object_get_pointers(enum rt_object_class_type type, rt_object_t *pointers, int maxlen)
{
int index = 0;
rt_ubase_t level;
struct rt_object *object;
struct rt_list_node *node = RT_NULL;
struct rt_object_information *information = RT_NULL;
if (maxlen <= 0) return 0;
information = rt_object_get_information((enum rt_object_class_type)type);
if (information == RT_NULL) return 0;
level = rt_hw_interrupt_disable(); //关中断
/* 遍历对象指针 */
rt_list_for_each(node, &(information->object_list))
{
object = rt_list_entry(node, struct rt_object, list);
pointers[index] = object;
index ++;
if (index >= maxlen) break;
}
rt_hw_interrupt_enable(level); //开中断
return index;
}
4、IPC对象
Rt-Thread中IPC对象有信号量,互斥量,事件集,邮箱,消息队列。
4.1、IPC控制块
IPC控制块由rt_object继承而来。并且拥有一个线程等待链表,用于保存因获取不到资源而挂起的线程。
struct rt_ipc_object
{
struct rt_object parent; /* 对象 */
rt_list_t suspend_thread; /* 线程挂起链表 */
};
4.2、函数
4.2.1、rt_ipc_object_init()函数
此函数用于初始化ipc对象。
rt_inline rt_err_t rt_ipc_object_init(struct rt_ipc_object *ipc)
{
rt_list_init(&(ipc->suspend_thread)); //初始化ipc的线程挂起链表
return RT_EOK; //返回RT_EOK
}
4.2.2、rt_ipc_list_resume()函数
此函数用于唤醒一个因获取不到IPC对象资源而挂起的线程。
1)根据链表节点获取要唤醒的线程控制块
2)唤醒线程
rt_inline rt_err_t rt_ipc_list_resume(rt_list_t *list)
{
struct rt_thread *thread;
thread = rt_list_entry(list->next, struct rt_thread, tlist); //获取线程
RT_DEBUG_LOG(RT_DEBUG_IPC, ("resume thread:%s\n", thread->name)); //打印信息
rt_thread_resume(thread); //唤醒线程
return RT_EOK; //返回RT_EOK
}
4.2.3、rt_ipc_list_resume_all()函数
此函数用于唤醒因获取不到IPC对象资源而挂起的所有线程,且将线程错误码设置为RT_ERROR。
1)对因获取不到IPC对象资源而挂起的所有线程进行操作
2)将线程错误码设置为RT_ERROR
3)唤醒线程
rt_inline rt_err_t rt_ipc_list_resume_all(rt_list_t *list)
{
struct rt_thread *thread;
register rt_ubase_t temp;
/* 唤醒所有挂起的线程 */
while (!rt_list_isempty(list))
{
temp = rt_hw_interrupt_disable(); //关中断
thread = rt_list_entry(list->next, struct rt_thread, tlist); //获取下一个挂起的线程
thread->error = -RT_ERROR; //将线程错误码设置为RT_ERROR
rt_thread_resume(thread); //唤醒线程
rt_hw_interrupt_enable(temp); //开中断
}
return RT_EOK; //返回RT_EOK
}
4.2.4、rt_ipc_list_suspend()函数
此函数将挂起一个线程到指定的列表。
1)挂起线程
2)如果flag为RT_IPC_FLAG_FIFO,将当前线程放到挂起线程链表的最后。
3)如果flag为RT_IPC_FLAG_PRIO,根据优先级在挂起链表list中查找合适的位置插入。
rt_inline rt_err_t rt_ipc_list_suspend(rt_list_t *list,
struct rt_thread *thread,
rt_uint8_t flag)
{
rt_thread_suspend(thread); //挂起线程
switch (flag)
{
case RT_IPC_FLAG_FIFO: //根据先进先出
rt_list_insert_before(list, &(thread->tlist)); //将当前线程放到挂起线程链表的最后
break;
case RT_IPC_FLAG_PRIO: //根据优先级
{
struct rt_list_node *n;
struct rt_thread *sthread;
/* 根据优先级查找合适的位置 */
for (n = list->next; n != list; n = n->next)
{
sthread = rt_list_entry(n, struct rt_thread, tlist); //获取线程
if (thread->current_priority < sthread->current_priority) //优先级比较
{
/* 在sthread线程前插入此线程 */
rt_list_insert_before(&(sthread->tlist), &(thread->tlist)); //插入
break;
}
}
/* 没有找到合适的位置 */
if (n == list)
rt_list_insert_before(list, &(thread->tlist)); //将当前线程放到挂起线程链表的最后
}
break;
}
return RT_EOK; //返回RT_EOK
}