RTT内核启动之rt_system_timer_init系统定时器初始化

RTT内核启动之rt_hw_board_init硬件板级初始化函数-CSDN博客这篇文章中,我们介绍完了板级硬件初始化函数,这篇文章中我们继续介绍系统定时器的初始化函数。

rt_timer_list定时器列表

与定时器相关的有一个很重要的系统定时器列表,他在timer.c文件中被定义:

/* hard timer list */
static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL];

这是一个rt_list_t类型(该类型是一个双向链表)的数组,数组大小由宏RT_TIMER_SKIP_LIST_LEVEL来决定,这个宏在rtdef.h文件中被定义,默认情况下这个宏数值为1,也就是数组大小就是1,即数组只有一个成员。

/**
 * Double List structure
 */
struct rt_list_node
{
    struct rt_list_node *next;                          /**< point to next node. */
    struct rt_list_node *prev;                          /**< point to prev node. */
};
typedef struct rt_list_node rt_list_t;                  /**< Type for lists. */

在这里插入图片描述

内核对象定时器rt_timer结构体

除此之外我们再来说一下内核对象定时器rt_timer结构体的相关内容,下面是这个结构体的原型以及时钟和定时器的一些相关的宏定义:
在这里插入图片描述

最后一行中,我们定义了一个新的类型别名:rt_timer_t,它实际上是struct rt_timer *类型的结构体指针。

我们先来解释一些结构体中的一些变量。

  1. parent
    第一个结构体类型变量:parent,这里通过定义一个“父类”的结构体变量,实现了类似面向对象编程中继承的概念,继承了RTT的内核对象。

因为定时器也属于内核对象,也会在自身结构体里面包含一个内核对象类型的成员,通过这个成员可以将定时器挂到系统对象容器中。

上面这句高亮的部分是我在查阅相关资料的时候在野火的RTT教程中看到的一句话。至于如何通过这个成员将定时器挂到系统对象容器中,我的猜测是这样的(仅仅是个人的猜测,还没有详细的研究这一部分代码):

在timer.c文件中,有这么一个定时器初始化函数,下面是函数原型:

/**
 * This function will initialize a timer, normally this function is used to
 * initialize a static timer object.
 *
 * @param timer the static timer object
 * @param name the name of timer
 * @param timeout the timeout function
 * @param parameter the parameter of timeout function
 * @param time the tick of timer
 * @param flag the flag of timer
 */
void rt_timer_init(rt_timer_t  timer,
                   const char *name,
                   void (*timeout)(void *parameter),
                   void       *parameter,
                   rt_tick_t   time,
                   rt_uint8_t  flag)
{
    /* timer check */
    RT_ASSERT(timer != RT_NULL);

    /* timer object initialization */
    rt_object_init((rt_object_t)timer, RT_Object_Class_Timer, name);

    _rt_timer_init(timer, timeout, parameter, time, flag);
}
RTM_EXPORT(rt_timer_init);

我们可以注意到这个函数中还嵌套了一个内核对象的初始化函数rt_object_init,下面是这个函数的原型:

/**
 * 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_HOOK_CALL(rt_object_attach_hook, (object));这个宏定义应该起到了将定时器挂在到了系统对象容器中的作用。这个宏首先”CALL“了一个钩子函数,然后调用了rt_object_attach_hook这个钩子函数,根据这个钩子函数的命名,我们可以大概的猜到他的作用:将内核对象attach(连接)到了系统对象容器。

  1. row[RT_TIMER_SKIP_LIST_LEVEL]
    这也是一个rt_list_t类型的数组,是定时器自身的结点,通过该结点可以实现将定时器插入到系统定时器列表,数组的长度是由宏RT_TIMER_SKIP_LIST_LEVEL来决定,默认情况下数组长度为1。

  2. void (*timeout_func)(void *parameter);
    这是一个超时回调函数指针,用于处理定时器溢出事件。

  3. void *parameter;
    这是超时回调函数需要的参数,从而实现处理可变参数的函数。

  4. init_tick
    这个变量是定时实际需要延时的时间,单位是tick。

  5. timeout_tick
    这个变量储存的是当定时器达到延时时间后系统时基计数器rt_rick(在clock.c文件中被定义)的实际值,也就是定时器的超时时刻。举个例子,假设有一个线程需要延时10个tick,那么init_tick=10,而此时的rt_tick如果是12,那么这时候timeout_tick就等于init_tick + rt_tick=22。

我们再来看系统定时器的初始化函数:

/**
 * @ingroup SystemInit
 *
 * This function will initialize system timer
 */
void rt_system_timer_init(void)
{
    int i;

    for (i = 0; i < sizeof(rt_timer_list) / sizeof(rt_timer_list[0]); i++)
    {
        rt_list_init(rt_timer_list + i);
    }
}

这个初始化函数先遍历了系统定时器列表,然后将定时器列表中的每一个结点都进行了初始化
这样做的好处有很多:

1. 链表的自包含性

将链表节点的 nextprev 都指向自身,使得该节点在逻辑上形成了一个空链表的形式。这样,单个节点就可以表示一个独立的空链表,这种自包含性使得链表操作更加简洁和一致。

rt_inline void rt_list_init(rt_list_t *l) { l->next = l->prev = l; }

2. 简化链表操作

初始化后的节点可以直接作为链表操作的起点,无需额外的检查和特殊处理。例如,在插入、删除节点时,可以统一处理而不需要区分节点是否已经在链表中或链表是否为空。

3. 避免空指针问题

将节点的 nextprev 初始化为指向自身,有助于避免链表操作中常见的空指针引用问题。在操作空链表或单节点链表时,不会因为未初始化的指针而发生崩溃。

4. 提高代码可读性

这种初始化方式使链表初始化代码更加直观,易于理解和维护。开发人员可以明确知道一个新初始化的节点是独立的,不属于任何链表。

5. 一致性检查

通过检查节点的 nextprev 是否指向自身,可以快速判断一个节点是否是一个独立的空链表的一部分。这对于调试和确保链表操作的一致性非常有用。

另外链表的初始化函数在rtservice.c文件中被定义,这个文件中储存的是操作系统服务层函数。例如链表的增删改查函数。

/**
 * @brief initialize a list
 *
 * @param l list to be initialized
 */
rt_inline void rt_list_init(rt_list_t *l)
{
    l->next = l->prev = l;
}

在rt_system_timer_init函数对系统定时器初始化完成之后,后面的rt_system_timer_thread_init函数将会对系统定时器线程进行初始化并启动这一线程。

  • 16
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`struct rtable`是Linux内核中用于表示路由表项的结构体,它包含了以下字段: - `struct dst_entry dst`:表示路由目标的抽象结构,包含了一些通用的目标路由信息; - `int rt_flags`:表示路由表项的一些标志位,例如是否是主机路由表项、是否启用了源地址验证等; - `unsigned int rt_priority`:表示路由表项的优先级,用于决定路由选择时的权重; - `u32 rt_iif`:表示数据包进入的接口,用于数据包的转发和路由选择; - `struct net_device *rt_dev`:表示数据包要从哪个网络设备出去; - `struct rtable *u`:表示指向上一级路由的指针,通常用于实现路由缓存; - `struct flowi fl`:表示流信息,包含了要进行路由选择所需要的源、目的地址、服务类型等信息; - `struct rt6_info *rt6i`:表示IPv6路由表项的信息; - `struct fib_info *fib_info`:表示当前路由表的信息,包括了路由表的ID等; - `int arp_status`:表示路由表项的ARP状态; - `unsigned long rt_genid`:表示路由表项的生成ID; - `void *peer`:表示路由表项对应的邻居设备; - `struct neigh_parms *parms`:表示路由表项对应的邻居设备的参数; - `struct hh_cache *hh`:表示硬件地址缓存,用于提高路由性能; - `int rt_metric`:表示路由表项的度量值,用于决定路由选择时的优先级; - `unsigned long rt_mtu`:表示路由表项对应的最大传输单元; - `u32 rt_window`:表示路由表项对应的窗口大小,通常用于TCP拥塞控制; - `u32 rt_ssthresh`:表示路由表项对应的慢启动阈值,通常用于TCP拥塞控制; - `u32 rt_tos`:表示路由表项对应的服务类型; - `u32 rt_mark`:表示路由表项对应的标记; - `u32 rt_via_tos`:表示路由表项对应的网关服务类型; - `u32 rt_irtt`:表示路由表项对应的初始往返时间(Initial Round-Trip Time); - `u32 rt_pmtu`:表示路由表项对应的路径最大传输单元(Path MTU); - `u32 rt_hoplimit`:表示路由表项对应的跳数限制,通常用于IPv6; - `u32 rt_rxhash`:表示路由表项对应的数据包接收哈希值; - `struct timer_list rt_timer`:表示路由表项的计时器,用于实现路由缓存; - `struct timer_list rt_advise_timer`:表示路由表项的建议计时器; - `unsigned long rt_rmx[RTAX_MAX]`:表示路由表项的一些额外信息,例如RTT(Round-Trip Time)等; - `unsigned long rt_cpu`:表示路由表项所在的CPU编号; - `struct rcu_head rcu`:表示RCU(Read-Copy Update)头,用于实现无锁读写操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值