**
* The object type can be one of the follows with specific
* macros enabled:
* - Thread
* - Semaphore
* - Mutex
* - Event
* - MailBox
* - MessageQueue
* - MemHeap
* - MemPool
* - Device
* - Timer
* - Module
* - Unknown
* - Static
*/
enum rt_object_class_type
{
RT_Object_Class_Thread = 0, /**< The object is a thread. */
RT_Object_Class_Semaphore, /**< The object is a semaphore. */
RT_Object_Class_Mutex, /**< The object is a mutex. */
RT_Object_Class_Event, /**< The object is a event. */
RT_Object_Class_MailBox, /**< The object is a mail box. */
RT_Object_Class_MessageQueue, /**< The object is a message queue. */
RT_Object_Class_MemHeap, /**< The object is a memory heap */
RT_Object_Class_MemPool, /**< The object is a memory pool. */
RT_Object_Class_Device, /**< The object is a device */
RT_Object_Class_Timer, /**< The object is a timer. */
RT_Object_Class_Module, /**< The object is a module. */
RT_Object_Class_Unknown, /**< The object is unknown. */
RT_Object_Class_Static = 0x80 /**< The object is a static object. */
};
对象类型的枚举定义就如上面的一般,线程,信号量···这些全部使用rt_object_class_type的枚举类型来表示。这里是即将开启对象容器的第一步,对象容器使用来管理这些数据类型,书里说利用finsh组件时候,就会扫描容器内的内核对象。
list_thread
thread pri status sp stack size max used left tick error
------ --- ------- ---------- ---------- ------ ---------- ---
tshell 20 ready 0x00000080 0x00001000 09% 0x00000006 000
tidle 31 ready 0x00000054 0x00000100 35% 0x0000000b 000
msh >list_device
device type ref count
------ -------------------- ----------
uart1 Character Device 2
pin Miscellaneous Device 0
msh >list_sem
semaphore v suspend thread
-------- --- --------------
shrx 000 0
heap 001 0
msh >
至少我在第一次使用的时候,是十分惊讶的,以为那么高级的功能只有Windows和Linux这种大型系统才能使用。
当然,只是对对象类型的格式定义还不能做什么,虽然每个对象都有自己的编号但实际上,如果需要管理还需要加入容器,容器的实现在RT-Thread中是一个二维数组实现的。这个数组的名字是rt_object_container[RT_Object_container[RT_Object_Info_Unknow],它是一个二维数组,你可以理解每一个对象是行元素,对象中每一个元素是列元素。每一行列元素内包含什么信息呢?
/**
* The information of the kernel object
*/
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 */
};
现在就可以看这个容器的样子了,样子是这样的
tatic 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
};
里面除了RT_Object_Class_Timer和RT_Object_Class_Thread之外,全部是有条件编译限制的,可以理解为Thread和Timer是RT-Tread中不可或缺的部分,也就是可以理解为其他的部分,并不是必选项,这个容器的大小是可以变化的。容器的大小就由RT_Object_Info_Unknow来决定。哪谁来决定RT_Object_Info_Unknow的大小呢?
/*
* define object_info for the number of rt_object_container items.
*/
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. */
#ifdef RT_USING_MODULE
RT_Object_Info_Module, /**< The object is a module. */
#endif
RT_Object_Info_Unknown, /**< The object is unknown. */
};
从这里我们可以知道RT-Object_Info_Unknow的大小就是由宏定义开启多少功能来决定的。所以说,RT_Object_Info_Unknown的大小最小为2,最大为12。
类似于优先级列表的实现,优先级利用一个长度为RT_THREAD_PRIORITY_MAX的一维数组就为我们分开了优先级不同的线程在各自的优先级链表里。容器的实现是一个二维数组。他的样子更像是这样:
object.c文件是在Kernel文件夹下的,使用容器,需要用到容器接口,就如我们拿finish举过例子。例如,我们想找容器中的thread对象,我们应该怎么用呢?
用rt_object_get_information()函数
/**
* This function will return the specified type of object information.
*
* @param type the type of object
* @return the object type information or RT_NULL
*/
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;
}
for循环遍历,因为使用宏定义会屏蔽掉一下不使用的功能,所以,用for循环遍历,而不是用switch语句。
/**
* 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_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);
/* 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);
}
rt_object_init()函数还记得出现在哪里吗?
出现在rt_thread_init函数里的
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_object_init((rt_object_t)thread,RT_Object_Class_Thread,name);
rt_list_init(&(thread->tlist);
}
- 第一次使用CSDN的MakeDown编辑器来编辑文档,讲道理,还是有些生疏的。
- RT-Thread讲道理对我来说,还是相当复杂的东西,限于自身能力的原因,在理解方面还是有些不太能Get到源码的点
- 讲道理,写到这里已经是包含了线程的定义,优先级的实现,简单的不涉及优先级的调度以及对象容器的实现
1.每个线程都会被挂在优先级列表上,优先级列表是为了解决多任务调度优先处理紧急任务的作用
2.每个线程都会被挂在对象容器上,对象容器是为了便于管理线程的运行状态,可以用finish输出对象的信息
3.这个表肯定是不完善的,其实,还有更多的信息。对于一个semaphore来说,它本身只是一个拥有rt_ipc_object对象和一个value的信息量值罢了,它本身只是一个对象,所有对它的操作,都将在thread中运行。所以对于一个包含了semaphore操作的线程来说,线程需要执行一次rt_object_init()来将线程挂在到对象容器中,semaphore也将执行rt_object_init()来将自己插入到对象容器中 对象都包括哪些 RT-Thread中,所有的数据结构都称之为对象