rtthread对象容器的实现

31 篇文章 4 订阅

title: rtthread对象容器的实现
date: 2020-10-22 15:50:29
tags: rtthread


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

对象

对象枚举定义

中线程,信号量,互斥量、事件、邮箱、消息队列、内存堆、内存池、设备和定时器在 rtdef.h 中有明显的枚举定义。

rtdef.h

/**
 * 对象类型由下面的宏来使能,这些宏通常在rtconfig.h中定义
 *  - Thread
 *  - Semaphore
 *  - Mutex
 *  - Event
 *  - MailBox
 *  - MessageQueue
 *  - MemHeap
 *  - MemPool
 *  - Device
 *  - Timer
 *  - Module
 *  - Unknown
 *  - Static
 */
enum rt_object_class_type
{
     RT_Object_Class_Thread = 0,       /* 对象是线程 */
     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     /* 对象是静态对象 */
};

对象数据类型

/**
 * 内核对象基础数据结构
 */
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;                  /*内核对象数据类型重定义 */

**对象的列表节点:**每个对象都可以通过自己的列表节点 list 将自己挂到容器列表中

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

rtdef.h

/*
*************************************************************************
*                               线程结构体
*************************************************************************
*/

struct rt_thread
{
    /* rt 对象 */
    char        name[RT_NAME_MAX];    /* 对象的名字 */
    rt_uint8_t  type;                 /* 对象类型 */
    rt_uint8_t  flags;                /* 对象的状态 */
    rt_list_t   list;                 /* 对象的列表节点 */
    
	rt_list_t   tlist;                /* 线程链表节点 */
    
	void        *sp;	              /* 线程栈指针 */
	void        *entry;	              /* 线程入口地址 */
	void        *parameter;	          /* 线程形参 */	
	void        *stack_addr;          /* 线程起始地址 */
	rt_uint32_t stack_size;           /* 线程栈大小,单位为字节 */	
};
typedef struct rt_thread *rt_thread_t;

容器

在 rtt 中,每当用户创建一个对象,如线程,就会将这个对象放到一个叫做容器的地方,这样做的目的是为了方便管理。在 RT-Thread 的组件 finsh 的使用中,就需要使用到容器,通过扫描容器的内核对象来获取各个内核对象的状态,然后输出调试信息。

定义

容器就是一个数组,是一个全局变量。数据类型为 struct rt_object_information。数组每一个成员代表一种类型

object.c

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_module)
    },
#endif
		
};

目前没有加定时器,先注释掉。

对象容器示意图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7o9B1pB3-1608216037994)(https://i.loli.net/2020/10/22/RUHcTFwzD9lGhI8.png)]

对象信息数据类型

容器是一个全局变量的数组,数据类型为 struct rt_object_information,这是一个结构体类型,包含对象的三个信息,分别为对象类型、对象列表节点头和对象的大小。

rtdef.h

/**
 * 内核对象信息结构体
 */
struct rt_object_information
{
    enum rt_object_class_type type;                     /* 对象类型 */
    rt_list_t                 object_list;              /* 对象列表节点 */
    rt_size_t                 object_size;              /* 对象大小 */
};

rt_object_info_type枚举

object.c

/*
 * 对象容器数组的下标定义,决定容器的大小
 */
enum rt_object_info_type
{
    RT_Object_Info_Thread = 0,                         /* 对象是线程 */
#ifdef RT_USING_SEMAPHORE
    RT_Object_Info_Semaphore,                          /* 对象是信号量 */
#endif
#ifdef RT_USING_MUTEX
    RT_Object_Info_Mutex,                              /* 对象是互斥量 */
#endif
#ifdef RT_USING_EVENT
    RT_Object_Info_Event,                              /* 对象是事件 */
#endif
#ifdef RT_USING_MAILBOX
    RT_Object_Info_MailBox,                            /* 对象是邮箱 */
#endif
#ifdef RT_USING_MESSAGEQUEUE
    RT_Object_Info_MessageQueue,                       /* 对象是消息队列 */
#endif
#ifdef RT_USING_MEMHEAP
    RT_Object_Info_MemHeap,                            /* 对象是内存堆 */
#endif
#ifdef RT_USING_MEMPOOL
    RT_Object_Info_MemPool,                            /* 对象是内存池 */
#endif
#ifdef RT_USING_DEVICE
    RT_Object_Info_Device,                             /* 对象是设备 */
#endif
    RT_Object_Info_Timer,                              /* 对象是定时器 */
#ifdef RT_USING_MODULE
    RT_Object_Info_Module,                             /* 对象是模块 */
#endif
    RT_Object_Info_Unknown,                            /* 对象未知 */
};

_OBJ_CONTAINER_LIST_INIT()宏定义

_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)}

容器的接口实现

获取指定类型的对象信息

从容器中获取指定类型的对象的信息

/**
 * 获取指定类型的对象信息
 *
 * @param type 对象类似
 * @return 对象信息 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;
}

容器在定义的时候,大小是被固定的,由 RT_Object_Info_Unknown 这个枚举值决定,但容器里面的成员是否初始化就不一定了,其中线程和定时器这两个对象默认会被初始化,剩下的其它对象由对应的宏决定。rt_object_get_information()会遍历整个容器对象,如果对象的类型等于我们指定的类型,那么就返回该容器成员的地址,地址的类型为 struct rt_object_information。

对象的初始化

  1. 从容器里拿到对应对象列表头指针
  2. 设置对象类型为静态
  3. 设置对象名字,一般与线程名字一样
  4. 将对象插入到容器的对应列表中

object.c

/**
 * 该函数将初始化对象并将对象添加到对象容器中
 *
 * @param object 要初始化的对象
 * @param type 对象的类型
 * @param name 对象的名字,在整个系统中,对象的名字必须是唯一的
*/
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;

    /* 获取对象信息,即从容器里拿到对应对象列表头指针 */
    information = rt_object_get_information(type);

    /* 设置对象类型为静态 */
    object->type = type | RT_Object_Class_Static;

    /* 拷贝名字 */
    rt_strncpy(object->name, name, RT_NAME_MAX);

    /* 关中断 */
    temp = rt_hw_interrupt_disable();

    /* 将对象插入到容器的对应列表中,不同类型的对象所在的列表不一样 */
    rt_list_insert_after(&(information->object_list), &(object->list));

    /* 使能中断 */
    rt_hw_interrupt_enable(temp);
}

kservice.c

/**
 * 该函数将指定个数的字符串从一个地方拷贝到另外一个地方
 * 
 * @param dst 字符串拷贝的目的地
 * @param src 字符串从哪里拷贝
 * @param n 要拷贝的最大长度
 *
 * @return the result
 */
char *rt_strncpy(char *dst, const char *src, rt_ubase_t n)
{
    if (n != 0)
    {
        char *d = dst;
        const char *s = src;

        do
        {
            if ((*d++ = *s++) == 0)
            {
                /* NUL pad the remaining n-1 bytes */
                while (--n != 0)
                    *d++ = 0;
                break;
            }
        } while (--n != 0);
    }

    return (dst);
}

在容器中插入两个线程对象如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b07iLGnV-1608216037999)(https://i.loli.net/2020/10/22/JykelF2bR3CAVqZ.png)]

调用对象初始化函数

对象初始化函数在线程初始化函数里面被调用。在线程初始化之后,线程通过自身的 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_object_t类型 */
	rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);
    rt_list_init(&(thread->tlist));
	
	thread->entry = (void *)entry;
	thread->parameter = parameter;

	thread->stack_addr = stack_start;
	thread->stack_size = stack_size;
	
	/* 初始化线程栈,并返回线程栈指针 */
	thread->sp = (void *)rt_hw_stack_init( thread->entry, 
		                                   thread->parameter,
							               (void *)((char *)thread->stack_addr + thread->stack_size - 4) );
	
	return RT_EOK;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值