RT-Thread对象容器的实现

什么是对象

在RT-Thread中,所有的数据结构都称之为对象

对象枚举定义

其中线程,信号量、互斥量、事件、邮箱、消息队列、内存堆、内存池、设备和定时器在rtdef.h中有明显的枚举定义,即为每个对象打上了一个数字标签。

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. */
};

对象数据类型定义

在RTT中,为了方便管理这些对象,专门定义了一个对象数据类型结构,具体见下面的代码

/**
 * Base structure of Kernel object
 */
struct rt_object
{
    char       name[RT_NAME_MAX];       (1)                /**< name of kernel object */
    rt_uint8_t type;                    (2)              /**< type of kernel object */
    rt_uint8_t flag;                    (3)                /**< flag of kernel object */

#ifdef RT_USING_MODULE
    void      *module_id;                               /**< id of application module */
#endif
    rt_list_t  list;                     (4)          /**< list node of kernel object */
};
typedef struct rt_object *rt_object_t;                  /**< Type for kernel objects. */

(1):对象名字,字符串形式,方便调试,最大长度由rt_config.h中的宏RT_NAME_MAX决定,默认长度为8.

(2):对象的类型,RT-Thread为每一个对象都打上了数字标签,取值由rt_object_class_type枚举类型限定。

(3):对象的状态

(4):对象的列表节点,每个对象都可以通过自己的列表节点list将自己挂到容器列表中,什么是容器,下文中将会进行解释。

(5):对象数据类型,RT-Thread中会为每一个新的结构体用typedef 重定义一个指针类型的数据结构。

在线程控制块中添加对象成员

在RT-Thread中,每个对象都会有对应的一个结构体,这个结构体叫做该对象的控制块,如线程会有一个线程控制块,定时器会有一个定时器控制块,信号量会有一个信号量控制块等。这些控制块的开头都会包含一个内核对象结构体,或者直接将对象结构体的成员放在对象控制块结构体的开头,其中线程控制块的开头放置的就是对象结构体的成员,如下代码所示,其余都是直接在控制块的开头直接使用struct rt_object直接定义一个内核对象变量。

线程控制块的开头,对象的结构体成员

struct rt_thread
{
    /* rt object */
    char        name[RT_NAME_MAX];                      /**< the name of thread */
    rt_uint8_t  type;                                   /**< type of object */
    rt_uint8_t  flags;                                  /**< thread's flags */

    rt_list_t   list;                                   /**< the object list */

什么是容器

在RTT中,每当用户创建一个对象,如线程, 就会将这个对象放到一个叫做容器的地方,这样做的目的是为了方便管理,这时你可能会问,管理什么?在RT-Thread的组件finsh的使用中,就需要使用到容器,通过扫描容器的内核对象来获取各个内核对象的状态,然后输出调试信息,目前,我们只需要知道所有创建的对象都会被放到容器中即可。

那什么是容器,从代码上来看,容器就是一个数组,是一个全局变量,数据类型为struct rt_object_information,在object.c中定义,具体见下面代码所示

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
};

对象容器是一个全局变量的数组,数据类型为struct rt_object_information,这是一个结构体类型,包含对象的三个信息,分别为对象类型,对象列表节点头和对象的大小,在rt_def.h中定义,具体实现见下面代码所示

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 */
};

 (1)对象的类型,取值只能是rt_object_class_type枚举类型,具体取值见上面列出的枚举体

(2)对象列表节点头,每当对象创建的时候,对象就会通过他们控制块里面的list节点将自己挂到对象容器中同一个对象列表中,容器数组的小标就是对象的类型。

(3)对象的大小,可直接通过sizeof(对象控制块类型)获取。

容器的大小直接由RT_Object_Info_Unknown决定,RT_Object_Info_Unknown是一个枚举体类型的变量,在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. */
#ifdef RT_USING_MODULE
    RT_Object_Info_Module,                             /**< The object is a module. */
#endif
    RT_Object_Info_Unknown,                            /**< The object is unknown. */
};

#define _OBJ_CONTAINER_LIST_INIT(c)     \
    {&(rt_object_container[c].object_list), &(rt_object_container[c].object_list)}
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
};

可以看出,RT_Object_Info_Unknown 位于枚举结构体的最后,它的具体取值由前面的成员多少决定,前面的成员是否有效都是通过宏定义来实现的,只有在rtconfig.h中定义了相应的宏,对应的枚举体成员才会有效,默认在这些宏都没有定义的情况下只有RT_Object_Info_Thread和RT_Object_Info_Timer有效,此时RT_Object_Info_Unknown的值等于2,当这些宏全部有效,此时RT_Object_Info_Unknown的值等于2,这些宏全部有效,RT_Object_Info_Unknown的值等于11,即容器的大小是12,此时是最大的,C语言知识,如果枚举体类型成员值没有具体指定,那么最后一个值是在前一个成员值的基础上加一。

初始化对象容器——线程,线程是RTT中最基本的对象,是必须存在的,它和其他对象不一样,没有通过宏来选择,接下来下面的信号量,邮箱都通过对应的宏定义来控制是否初始化,即只有在创建了相应的对象之后,才在对象容器里面初始化。

初始化对象类型为线程。

初始化对象列表节点头里面的next和prev两个节点指针分别指向自身。

容器的接口实现

获取指定类型的对象信息

从容器中,获取指定类型的对象的信息由函数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_Object_Info_Unknown这个枚举值决定,但容器里面的成员是否初始化就不一定了,其中线程和定时器这两个对象默认会被初始化,剩下的由其他对象的宏定义决定,rt_object_get_information() 会遍历整个容器对象,如果对象的类型等

于我们指定的类型,那么就返回该容器成员的地址,地址的类型为 struct rt_object_information
对象初始化
每创建一个对象,都需要先将其初始化,主要分成两个部分的工作,首先将对象控制块里面与
对象相关的成员初始化,然后将该对象插入到对象容器中
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);
}

调用对象初始化函数

对象初始化函数在线程初始化函数里面被调用, 。如 果创建了两个线程,在线程初始化之后,线程通过自身的 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);

    /* init thread object */
    rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值