RT-Thread 自动初始化机制

news2024/12/23 9:50:43

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段中,在系统启动后在程序中初始化;动态内核对象则是从内存堆中创建,而后手工做初始化。

/* 线程 1 的对象和运行时用到的栈 */
static struct rt_thread thread1;
static rt_uint8_t thread1_stack[512];

/* 线程 1 入口 */
void thread1_entry(void* parameter)
{
     int i;

    while (1)
    {
        for (i = 0; i < 10; i ++)
        {
            rt_kprintf("%d\n", i);

            /* 延时 100ms */
            rt_thread_mdelay(100);
        }
    }
}

/* 线程 2 入口 */
void thread2_entry(void* parameter)
{
     int count = 0;
     while (1)
     {
         rt_kprintf("Thread2 count:%d\n", ++count);

        /* 延时 50ms */
        rt_thread_mdelay(50);
    }
}

/* 线程例程初始化 */
int thread_sample_init()
{
     rt_thread_t thread2_ptr;
     rt_err_t result;

    /* 初始化线程 1 */
    /* 线程的入口是 thread1_entry,参数是 RT_NULL
     * 线程栈是 thread1_stack
     * 优先级是 200,时间片是 10 个 OS Tick
     */
    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);

    /* 创建线程 2 */
    /* 线程的入口是 thread2_entry, 参数是 RT_NULL
     * 栈空间是 512,优先级是 250,时间片是 25 个 OS Tick
     */
    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);
    /* 比如打印所有thread的名字 */
    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);
    /* 比如打印所有mutex的名字 */
    rt_kprintf("name:%s\n", mutex->parent.parent.name);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1041781.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

25814-2010 三聚氯氰 阅读笔记

声明 本文是学习GB-T 25814-2010 三聚氯氰. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了三聚氯氰的要求、采样、试验方法、检验规则以及标志、标签、包装、运输、贮存、安全、 安全技术说明书。 本标准适用于三聚氯氰的产品…

基于springboot+vue的大学生创新创业系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

idea 如何在命令行快速打开项目

背景 在命令行中从git仓库检出项目&#xff0c;如何在该命令行下快速用idea 打开当前项目&#xff0c;类似vscode 可以通过在项目根目录下执行 code . 快速打开当前项目。 步骤 以macos 为例 vim /usr/local/bin/idea 输入如下内容 #!/bin/sh open -na "IntelliJ IDE…

浅谈智能型电动机控制器在斯里兰卡电厂中的应用

摘要&#xff1a;传统的低压电动机保护是通过继电保护二次回路实现&#xff0c;但是我们结合电厂辅助控制设备的特点及其控制要求&#xff0c;推荐ARD2F智能型电动机控制器。以下综合介绍ARD2F智能型电动机控制器产品的特点及其智能化保护、测量、控制和通讯等。 Abstract: Th…

基于微信小程序的校园失物招领系统设计与实现(源码+lw+部署文档+讲解等)

前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb;…

PS7软件功能——相位、延迟测量

PicoScope 7 &#xff08;PS7&#xff09;软件增添了新的测量功能——测量相位之间的角度和延迟时间&#xff08;图1&#xff09;。 注&#xff1a;Phase- 相位&#xff1b;Delay - 延迟。 图1 相位测量 点击“Phase”&#xff0c;选择需要测量的通道&#xff0c;如下图选择的是…

idea 2021.2.3版本中隐藏target和.iml文件问题的解决

一 idea2021.2.3 版本隐藏文件 1.1 问题描述 添加隐藏文件内容后&#xff1a;没有可确定的保存按钮。无法实现添加隐藏文件。 1.2 解决办法 IDEA新建项目会自动生成一个.idea文件夹和.iml文件&#xff0c;开发中不需要对这两个文件修改&#xff0c;所以对以上文件进行隐藏处理…

重要采样的原理与实现

1. 引言 在雷达系统性能仿真时&#xff0c;由于雷达系统对虚警概率的要求&#xff0c;实现一定精度的仿真&#xff0c;所需要的Monte-Carlo实验次数将非常地高。重要采样可以在保障精度的前提下&#xff0c;大大降低Monte-Carlo实验次数。 网上有很多关于重要采样的原理介绍&…

94 # express 兼容老的路由写法

上一节实现了错误处理中间件&#xff0c;这一节来实现兼容老的路由写法 看个 express 的二级路由的例子 const express require("express"); const userRouter require("./routes/userRouter"); const articleRouter require("./routes/articleR…

AIGC: 区块链与数据安全

随着国家将区块链纳入战略发展规划&#xff0c;数字经济蓬勃发展。近年来&#xff0c;数据的流通成为了实体经济赋能的关键&#xff0c;而在这一过程中&#xff0c;区块链技术和数据安全变得至关重要。 中国已经成为全球最大的数据体&#xff0c;每天产生大量数据。数字经济已…

Unity 协程(Coroutine)的原理以及用法

目录 事件函数的执行顺序定义使用yield instruction中的子类 总结 参考链接 &#xff1a;Unity 5分钟基础的了解协程 事件函数的执行顺序 定义 定义&#xff1a;开启一段和主程序异步执行的逻辑异步执行&#xff1a;是指语句在异步执行模式下&#xff0c;各语句执行结束的顺序…

Python异步编程之web框架 异步vs同步 文件IO任务压测对比

主题&#xff1a;比较异步框架和同步框架在文件IO操作的性能差异python版本&#xff1a;python 3.8压测工具&#xff1a;locustweb框架&#xff1a;同步&#xff1a;flask 异步&#xff1a;aiohttp、starlette异步文件模块&#xff1a;aiofiles、anyio.Path请求并发量: 模拟10个…

EPICS sequencer状态机示例

状态机源代码&#xff1a; #define PVSYS "pvsysca" #define LIGHT "{prefix}:light" #define LIGHTON "{prefix}:lightOn" #define LIGHTOFF "{prefix}:lightOff" #define VOLTAGE "{prefix}:voltage" #define LO…

机器人过程自动化(RPA)入门 3. 顺序、流程图和控制流程

到目前为止&#xff0c;我们已经了解了RPA是什么&#xff0c;并且我们已经看到了通过记录任务的活动并运行它来训练UiPath机器人是多么简单。使用记录器的UiPath可以很容易地自动化日常任务。在我们开始自动化复杂的任务之前&#xff0c;让我们学习如何控制从一个到另一个的活动…

【算法分析与设计】算法概述

目录 一、学习要点二、算法的定义三、算法的性质四、程序(Program)五、问题求解(Problem Solving)六、算法的描述七、算法分析的目的八、算法复杂性分析&#xff08;一&#xff09;算法时间复杂性分析&#xff08;二&#xff09;算法渐近复杂性1、渐进上界记号-大O符号2、渐进下…

Prometheus+Grafana监控K8S集群(基于K8S环境部署)

文章目录 一、环境信息二、部署前准备工作三、部署Prometheus监控系统四、部署Node_exporter组件五、部署Kube_state_metrics组件六、部署Grafana可视化平台七、Grafana可视化显示Prometheus收集数据八、Grafana添加监控模板九、拓展 一、环境信息 1、服务器及K8S版本信息&…

现代卷积网络实战系列4:PyTorch从零构建VGGNet训练MNIST数据集

&#x1f308;&#x1f308;&#x1f308;现代卷积网络实战系列 总目录 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 1、MNIST数据集处理、加载、网络初始化、测试函数 2、训练函数、PyTorch构建LeNet网络 3、PyTorch从零构建AlexNet训练MNIST数据…

【7.Vue 利用Heatmap.js 制作自定义热力图】

1.效果 2.背景 需要根据后端检测的设备的数值显示设备周围的清洁度,用户希望用热力图的方式来显示,于是在网上找了资料,发现可以用Heatmap.js来实现。 Heatmap.js 官网:https://www.patrick-wied.at/static/heatmapjs/ 3.引入组件 安装Heatmap.js npm install Heatmap.…

京东(JD)——利用人工智能实现自动零售

京东(JD)是中国最大的在线零售商之一&#xff0c;也是一家以高科技和人工智能物流而闻名的公司&#xff0c;其人工智能物流系统包括无人机交付系统、自动配送快递车以及机器人自动化配送中心。 京东一直致力于将机器人用于尽可能多地实现零售业务的物理自动化。 1.京东的人工智…

Nginx WEB访问与Linux授权约束

看到所有文件的权限都是没有的&#xff0c;即便所有的权限都没有即使nginx做了配置&#xff0c;这些都是正确的。那么在浏览器真正去访问的时候是不能访问的。 [rootjenkins html]# ls -l total 4 drwxr-xr-x 2 root root 23 Sep 16 17:43 dist ---------- 1 root root 33 Sep …