返回顶部
首页 > 资讯 > 后端开发 > JAVA >RT-Thread 自动初始化机制
  • 588
分享到

RT-Thread 自动初始化机制

RT-Thread 2023-09-26 12:09:54 588人浏览 独家记忆
摘要

RT-Thread自动初始化机制 自动初始化机制是指初始化函数不需要被显示调用,只需要在函数定义处通过宏定义的方式进行申明,就会在系统启动过程中被执行。 例如在串口驱动中调用一个宏定义告知系统初始化需

RT-Thread自动初始化机制

自动初始化机制是指初始化函数不需要被显示调用,只需要在函数定义处通过宏定义的方式进行申明,就会在系统启动过程中被执行。

例如在串口驱动中调用一个宏定义告知系统初始化需要调用的函数,代码如下:

init rt_hw_usart_init(void){//注册串口1设备rt_hw_serial_reGISter(&serial1, "uart1",RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,uart);return 0;}INIT_BOARD_EXPORT(rt_hw_usart_init); //使用组件自动初始化机制

示例代码最后的INIT_BOARD_EXPORT(rt_hw_usart_init)表示使用自动初始化功能,按照这种方式,rt_hw_usart_init()函数就会被系统自动调用,那么它是在哪里被调用的?

在系统启动流程图中,有两个函数:rt_conponents_board_init()与rt_components_ini(),

在这里插入图片描述
其后的带底色方框内部的函数表示被自动初始化的函数,其中:

  1. board init functions为所有通过通过INIT_BOARD_EXPORT(fn)申明的初始化函数。
  2. “pre-initialization functions” 为所有通过 INIT_PREV_EXPORT(fn)申明的初始化函数。
  3. “device init functions” 为所有通过 INIT_DEVICE_EXPORT(fn) 申明的初始化函数。
  4. “components init functions” 为所有通过 INIT_COMPONENT_EXPORT(fn)申明的初始化函数。
  5. “enviroment init functions” 为所有通过 INIT_ENV_EXPORT(fn) 申明的初始化函数。
  6. “application init functions” 为所有通过 INIT_APP_EXPORT(fn)申明的初始化函数。

rt_components_board_init()函数执行的比较早,主要初始化相关硬件环境,执行这个函数时将会遍历通过INIT_BOARD_EXPORT(fn)申明的初始化函数表,并调用各个函数。

rt_conponents_init()函数会在操作系统运行起来之后创建的main线程里被调用执行,这个时候硬件环境和操作系统已经初始化完成,可以执行应用相关代码。

rt_conponents_init()函数会遍历通过剩下的其它几个宏申明的初始化函数表。

RT-Thread的自动初始化机制使用了自定义RTI符号段,将需要在启动时进行初始化的函数指针放到了该段中,形成了一张初始化函数表,在系统启动过程中会遍历该表,并调用表中的函数,达到自动初始化的目的。

用来实现自动初始化功能的宏接口定义详细描述如下表所示:

  1. INIT_BOARD_EXPORT(fn):非常早期的初始化,此时调度器还未启动。
  2. INIT_BOARD_EXPORT(fn):主要用于纯软件的初始化,没有太多依赖的函数。
  3. INIT_DEVICE_EXPORT(fn):外设驱动初始化相关,比如网卡设备。
  4. INIT_CONPONENTS_EXPORT(fn):组件初始化,比如文件系统或者LWIP。
  5. INIT_ENV_EXPORT(fn):系统环境初始化,比如挂载文件系统。
  6. INIT_APP_EXPORT(fn):应用初始化,比如GUI应用。

初始化函数主动通过这些宏接口进行申明,如INIT_BOARD_EXPORT(rt_hw_usart_init),链接器会自动收集所有被申明的初始化函数,放到RTI符号段,该符号段位于内存分布的RO段,该RTI符号段中的所有函数在系统初始化时会被自动调用。

静态对象和动态对象

RT-Thread内核采用面向对象的设计思想进行设计,系统级的基础设施都是一种内核对象,例如线程,信号量,互斥量,定时器等。内核对象分为两类:静态内核对象和动态内核对象。

静态内核对象通常放在RW段和ZI段中,在系统启动后在程序中初始化;动态内核对象则是从内存堆中创建,而后手工做初始化。

static struct rt_thread thread1;static rt_uint8_t thread1_stack[512];void thread1_entry(void* parameter){     int i;    while (1)    {        for (i = 0; i < 10; i ++)        {            rt_kprintf("%d\n", i);                        rt_thread_mdelay(100);        }    }}void thread2_entry(void* parameter){     int count = 0;     while (1)     {         rt_kprintf("Thread2 count:%d\n", ++count);                rt_thread_mdelay(50);    }}int thread_sample_init(){     rt_thread_t thread2_ptr;     rt_err_t result;            result = rt_thread_init(&thread1,"thread1",thread1_entry, RT_NULL,&thread1_stack[0], sizeof(thread1_stack),200, 10);        if (result == RT_EOK) rt_thread_startup(&thread1);            thread2_ptr = rt_thread_create("thread2",    thread2_entry, RT_NULL,    512, 250, 25);        if (thread2_ptr != RT_NULL) rt_thread_startup(thread2_ptr);    return 0;}

在这个例子中,thread1是一个静态线程对象,内存空间,包括线程控制块thread1与栈空间thread1_stack都是编译时决定的,因为代码中都不存在初始值,统一放在未初始化数据段中。
thread2运行中用到的空间都是动态分配的。

静态对象会占用RAM空间,不依赖于内存堆管理器,内存分配时间确定。动态对象则依赖于内存堆管理器,运行时申请RAM空间,当对象被删除后,占用的RAM空间被释放。

内核对象管理架构

RT-Thread采用内核对象管理系统来访问/管理所有内核对象,内核对象包含了内核中绝大部分设施,这些内核对象可以是静态分配的静态对象,也可以是从系统内存堆中分配的动态对象。

通过这种内核对象的设计方式,RT-Thread做到了不依赖于具体的内存分配方式,系统的灵活性得到极大的提高。

RT-Thread内核对象包括:线程,信号量,互斥量,事件,邮箱,消息队列和定时器,内存池,设备驱动等。
对象容器中包含了每类内核对象的信息,包括对象类型、大小等。对象容器给每类内核对象法分配了一个链表,所有的内核对象都被链接到该链表上。
在这里插入图片描述
在这里插入图片描述
此图显示了RT-Thread中各类内核对象的派生和继承关系。
对于每一种具体内核对象和对象控制块,除了基本结构外,还有自己的扩展属性(私有属性)。

例如对于线程控制块,在基类对象基础上进行扩展,增加了线程状态、优先级等属性。这些属性在基类对象的操作中不会用到,只有在与具体线程相关的操作中才会使用。
因此,从面向对象的观点,可以认为每一种具体对象是抽象对象的派生,继承了基本对象的属性并在此基础上扩展了与自己相关的属性。

这种设计方法的优点有:

  1. 提高了系统的可重用性和扩展性,增加新的对象类别很容易,只需要继承通用对象的属性再加少量扩展即可。
  2. 提供了统一的对象操作方式,简化了各种具体对象的操作,提高了系统的可靠性。

上图中由对象控制块rt_object派生出来的有:

  • 线程对象
  • 内存池对象
  • 定时器对象
  • 设备对象
  • IPC对象(Inter-Process Communication,进程间通信。IPC对象的作用是进行线程间同步与通信);由 IPC 对象派生出信号量、互斥量、事件、邮箱与消息队列、信号等对象。

对象控制块

内核对象控制块的数据结构

struct rt_object{//内核对象名称char name[RT_NAME_MAX];rt_uint8_t type;rt_uint8_t flag;rt_list_t list;}
enum rt_object_class_type{     RT_Object_Class_Thread = 0,             #ifdef RT_USING_SEMAPHORE    RT_Object_Class_Semaphore,              #endif#ifdef RT_USING_MUTEX    RT_Object_Class_Mutex,                  #endif#ifdef RT_USING_EVENT    RT_Object_Class_Event,                  #endif#ifdef RT_USING_MAILBOX    RT_Object_Class_MailBox,                #endif#ifdef RT_USING_MESSAGEQUEUE    RT_Object_Class_MessageQueue,           #endif#ifdef RT_USING_MEMPOOL    RT_Object_Class_MemPool,                #endif#ifdef RT_USING_DEVICE    RT_Object_Class_Device,                 #endif    RT_Object_Class_Timer,                  #ifdef RT_USING_MODULE    RT_Object_Class_Module,                 #endif    RT_Object_Class_Unknown,                    RT_Object_Class_Static = 0x80           };

如果是静态对象,对象类型的最高位将是1(是RT_Object_Class_Static与其他对象类型的或操作),否则就是动态对象,系统最多能够容纳的对象类别数目是127个。

内核对象容器的数据结构

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标识出来(每一类对象的具体实例,他们占有的内存块大小都是相同的)。

初始化对象

在使用一个未初始化的静态对象前必须先对其进行初始化。
初始化对象使用以下接口:

void rt_object_init(struct rt_object* object,enum rt_object_class_type type,const char* name)

当调用这个函数进行对象初始化时,系统会把这个对象放置到对象容器中进行管理,即初始化对象的一些参数,然后把这个对象节点插入到对象容器的对象链表中,对该函数的输入参数的描述如下表:

分配对象

上述描述的都是对象初始化、脱离的接口,都是面向对象内存块已经有的情况下,而动态的对象则可以在需要时申请,不需要时释放出内存空间给其他应用使用。

rt_object_t rt_object_allocate(enum  rt_object_class_type type ,   const  char*  name)

系统首先根据对象类型获取对象信息(特别是对象类型的大小信息以用于系统能够分配正确大小的内存数据块),而后从内存堆中分配对象所对应大小的内存空间,然后再对该对象进行必要的初始化,最后将其插入到它所在的对象容器链表中。

如何遍历内核对象

以遍历所有线程为例:

rt_thread_t thread = RT_NULL;struct rt_list_node *node = RT_NULL;struct rt_object_information *information = RT_NULL;information = rt_object_get_information(RT_Object_Class_Thread);rt_list_for_each(node, &(information->object_list)){    thread = (rt_thread_t)rt_list_entry(node, struct rt_object, list);        rt_kprintf("name:%s\n", thread->name);}

以遍历所有互斥量为例:

rt_mutex_t mutex = RT_NULL;struct rt_list_node *node = RT_NULL;struct rt_object_information *information = RT_NULL;information = rt_object_get_information(RT_Object_Class_Mutex);rt_list_for_each(node, &(information->object_list)){    mutex = (rt_mutex_t)rt_list_entry(node, struct rt_object, list);        rt_kprintf("name:%s\n", mutex->parent.parent.name);}

来源地址:https://blog.csdn.net/Caramel_biscuit/article/details/133239231

--结束END--

本文标题: RT-Thread 自动初始化机制

本文链接: https://www.lsjlt.com/news/418497.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • RT-Thread 自动初始化机制
    RT-Thread自动初始化机制 自动初始化机制是指初始化函数不需要被显示调用,只需要在函数定义处通过宏定义的方式进行申明,就会在系统启动过程中被执行。 例如在串口驱动中调用一个宏定义告知系统初始化需...
    99+
    2023-09-26
    RT-Thread
  • bash初始化机制
    这篇文章主要介绍了详解bash中的初始化机制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。Bash初始化文件...
    99+
    2023-06-05
  • 自动修改mysql5.7初始化密码
    mysql5.7为了安全考虑,初始化后root密码随机生成,密码放在error日志里面.分两步:第一步获取error.log密码.修改默认密码,passwd=`grep 'generate...
    99+
    2024-04-02
  • 详解bash中的初始化机制
    Bash初始化文件 交互式login shell 在下列情况下,我们可以获得一个login shell: uFJHrKxWJu 登录系统时获得的顶层shell,无论是通过本地终端登录,还是通过网络ssh登录。这种情...
    99+
    2022-06-04
    bash 初始化 bash 初始化机制
  • SQL Server 2017 AlwaysOn AG 自动初始化(六)
    在现有可用性组上停止某个辅助副本的自动种子设定在主副本上执行ALTER AVAILABILITY GROUP [<availability_group_name>]...
    99+
    2024-04-02
  • SQL Server 2017 AlwaysOn AG 自动初始化(十)
    创建自动种子设定的可用性组的性能考虑SQL Server 使用固定数目的线程进行自动种子设定。 在主实例中,SQL Server 对每个 LUN 使用一个线程来读取更改。 在辅助实例中,SQL Server...
    99+
    2024-04-02
  • SQL Server 2017 AlwaysOn AG 自动初始化(四)
    查看数据库同步进度如果数据库在为自动种子设定配置的可用性组中,你可以查询 sys.dm_hadr_automatic_seeding 系统视图来监视种子设定进度。 对于处于为自动种子设定配置的可用性组中的每...
    99+
    2024-04-02
  • SQL Server 2017 AlwaysOn AG 自动初始化(三)
    创建具有自动种子设定的可用性组1. 创建端点每个副本都需要一个镜像端点进行通信,默认TCP端口为5022。CREATE ENDPOINT [Hadr_endpoint] STATE=ST...
    99+
    2024-04-02
  • SQL Server 2017 AlwaysOn AG 自动初始化(五)
    暂时阻止主副本将更多的数据库种子设定到辅助副本可以拒绝可用性组创建数据库的权限。在辅助副本上执行ALTER AVAILABILITY GROUP [<availabili...
    99+
    2024-04-02
  • SQL Server 2017 AlwaysOn AG 自动初始化(七)
    在现有可用性组上启用某个辅助副本的自动种子设定 在主副本上执行ALTER AVAILABILITY GROUP [<availability_group_nam...
    99+
    2024-04-02
  • SQL Server 2017 AlwaysOn AG 自动初始化(八)
    监控自动种子设定  系统动态管理视图 sys.dm_hadr_automatic_seeding 在主要副本上,查询 sys.dm_hadr_automatic_se...
    99+
    2024-04-02
  • SQL Server 2017 AlwaysOn AG 自动初始化(一)
    技术背景在 SQL Server 2012 和 2014 中,初始化 SQL Server Always On 可用性组中的次要副本的唯一方法是使用备份、复制和还原。SQL Server 2016 引入了用...
    99+
    2024-04-02
  • SQL Server 2017 AlwaysOn AG 自动初始化(二)
    必备条件文件路径要求在 SQL Server 2016 中,自动种子设定要求数据和日志文件路径在参与可用性组的每个 SQL Server 实例上均相同。 在 SQL Server 2017 中,你可以使用不...
    99+
    2024-04-02
  • SQL Server 2017 AlwaysOn AG 自动初始化(九)
    SQL Server VDI备份原理分析SQL Server提供了虚拟设备接口(VDI)API,用于帮助独立的应用程序提供商,支持将SQL Server的备份和恢复操作集成到他们的产品中。这些API设计为提...
    99+
    2024-04-02
  • SQL Server 2017 AlwaysOn AG 自动初始化(十六)
    总结对于咱们生产环境使用自动种子设定的考虑:由于SQL Server 2016和2017在磁盘文件路径要求中表现的行为不一样,2017能在主、辅助副本上让数据文件部署在不同的卷上,所以2017更灵活,更适合...
    99+
    2024-04-02
  • SQL Server 2017 AlwaysOn AG 自动初始化(十四)
    功能性测试测试自动种子设定对SQL Server 2017数据文件磁盘布局要求的变化由于生产环境存放数据文件可能位于不同的卷上,且实例名也不同,那么数据文件的完整路径就不同。为了能实现自动种子设定,重设默认...
    99+
    2024-04-02
  • SQL Server 2017 AlwaysOn AG 自动初始化(十二)
    何时不使用自动种子设定在某些情况下,自动种子设定可能不是初始化次要副本的最优选择。 自动种子设定过程中,SQL Server 通过网络执行备份以进行初始化。 如果数据库非常大或者次要副本是远程副本,此过程会...
    99+
    2024-04-02
  • SQL Server 2017 AlwaysOn AG 自动初始化(十一)
    何时不使用自动种子设定在某些情况下,自动种子设定可能不是初始化次要副本的最优选择。 自动种子设定过程中,SQL Server 通过网络执行备份以进行初始化。 如果数据库非常大或者次要副本是远程副本,此过程会...
    99+
    2024-04-02
  • SQL Server 2017 AlwaysOn AG 自动初始化(十三)
    其他需要知道的事情在自动种子设定期间事务日志不能被截断自动种子设定延迟日志截断。如果主副本上数据库负载很高,那么将显著产生大量日志,那么可能有填满日志文件的风险。当然大多数情况下日志文件设置为自动增长,没有...
    99+
    2024-04-02
  • SQL Server 2017 AlwaysOn AG 自动初始化(十五)
    性能测试对比分析拿xx库来做测试,数据文件8G,备份后为600M:测试场景使用时间1通过备份恢复来创建,开启备份压缩1分29秒2通过自动种子设定,开启备份压缩1分22秒3通过自动种子设定,开启备份压缩,开启...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作