IOT-OS之RT-Thread(四)--- 时钟管理与内存管理

本文详细探讨了RT-Thread操作系统中时钟管理和内存管理的实现。时钟管理主要依赖于时钟节拍systick,提供定时器对象管理,包括单次触发和周期触发定时器,以及硬软定时器模式。内存管理涉及内存堆和内存池,通过不同的管理算法如小内存管理、slab管理、memheap管理,确保高效、无碎片的内存分配。此外,内存池支持线程挂起功能,解决了内存不足时的等待问题。
摘要由CSDN通过智能技术生成

操作系统要想协调好各线程的调度管理,离不开时间与空间的管理:时间管理主要靠时钟节拍systick实现,时钟节拍是特定的周期性中断,这个中断可以看做是系统心跳(心跳频率一般设为10-1000HZ,时钟节拍率越快,系统额外开销越大),供系统处理所有和时间有关的事件,如线程的延时、线程的时间片轮转调度以及定时器超时等;空间管理主要是对可用存储空间的管理,一般MCU的存储空间可分为片内RAM与片内FLASH / ROM两种,片内RAM可由内存管理器动态分配/释放内部缓存空间(如Linux虚拟内存管理系统),片内FLASH可由文件系统进行分区分目录以文件为单位管理数据存储空间。

一、定时器对象管理

1.1 时钟节拍

时钟节拍定时器systick的配置和SysTick_Handler中断处理函数在前一篇CPU架构与BSP移植时已经简单介绍过了,下面再看看SysTick_Handler调用的rt_tick_increase函数代码:

// rt-thread-4.0.1\src\clock.c
static rt_tick_t rt_tick = 0;

/**
 * This function will notify kernel there is one tick passed. Normally,
 * this function is invoked by clock ISR.
 */
void rt_tick_increase(void)
{
   
    struct rt_thread *thread;

    /* increase the global tick */
#ifdef RT_USING_SMP
    rt_cpu_self()->tick ++;
#else
    ++ rt_tick;
#endif

    /* check time slice */
    thread = rt_thread_self();

    -- thread->remaining_tick;
    if (thread->remaining_tick == 0)
    {
   
        /* change to initialized tick */
        thread->remaining_tick = thread->init_tick;

        /* yield */
        rt_thread_yield();
    }

    /* check timer */
    rt_timer_check();
}

/**
 * This function will return current tick from operating system startup
 * @return current tick
 */
rt_tick_t rt_tick_get(void)
{
   
    /* return the global tick */
    return rt_tick;
}
RTM_EXPORT(rt_tick_get);

/**
 * This function will set current tick
 */
void rt_tick_set(rt_tick_t tick)
{
   
    rt_base_t level;

    level = rt_hw_interrupt_disable();
    rt_tick = tick;
    rt_hw_interrupt_enable(level);
}

/**
 * This function will calculate the tick from millisecond.
 * @param ms the specified millisecond
 *           - Negative Number wait forever
 *           - Zero not wait
 *           - Max 0x7fffffff
 * @return the calculated tick
 */
rt_tick_t rt_tick_from_millisecond(rt_int32_t ms)
{
   
    rt_tick_t tick;

    if (ms < 0)
    {
   
        tick = (rt_tick_t)RT_WAITING_FOREVER;
    }
    else
    {
   
        tick = RT_TICK_PER_SECOND * (ms / 1000);
        tick += (RT_TICK_PER_SECOND * (ms % 1000) + 999) / 1000;
    }
    /* return the calculated tick */
    return tick;
}
RTM_EXPORT(rt_tick_from_millisecond);

时钟节拍每次中断除了系统节拍全局变量rt_tick(rt_tick 的值表示了系统从启动开始总共经过的时钟节拍数,即系统时间)自增外,还调用了软件定时器检查函数rt_timer_check()来检查软件定时器链表中是否有定时器超时,若有则执行该定时器的超时函数,rt_timer_check()代码如下:

// rt-thread-4.0.1\src\timer.c

/**
 * This function will check timer list, if a timeout event happens, the
 * corresponding timeout function will be invoked.
 *
 * @note this function shall be invoked in operating system timer interrupt.
 */
void rt_timer_check(void)
{
   
    struct rt_timer *t;
    rt_tick_t current_tick;
    register rt_base_t level;

    RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check enter\n"));

    current_tick = rt_tick_get();

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

    while (!rt_list_isempty(&rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))
    {
   
        t = rt_list_entry(rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next,
                          struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]);

        /*
         * It supposes that the new tick shall less than the half duration of
         * tick max.
         */
        if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2)
        {
   
            RT_OBJECT_HOOK_CALL(rt_timer_enter_hook, (t));

            /* remove timer from timer list firstly */
            _rt_timer_remove(t);

            /* call timeout function */
            t->timeout_func(t->parameter);

            /* re-get tick */
            current_tick = rt_tick_get();

            RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t));
            RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));

            if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
                (t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
            {
   
                /* start it */
                t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
                rt_timer_start(t);
            }
            else
            {
   
                /* stop timer */
                t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
            }
        }
        else
            break;
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(level);

    RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check leave\n"));
}

rt_inline void _rt_timer_remove(rt_timer_t timer)
{
   
    int i;

    for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++)
    {
   
        rt_list_remove(&timer->row[i]);
    }
}

中断中的 rt_timer_check() 用于检查系统硬件定时器链表,如果有定时器超时,将调用相应的超时函数。且所有定时器在定时超时后都会从定时器链表中被移除,而周期性定时器会在它再次启动时被加入定时器链表。了解了软件定时器的超时检查过程和超时函数调用点,下面再看软件定时器的数据结构和接口函数。

1.2 定时器对象管理

定时器,是指从指定的时刻开始,经过一定的指定时间后触发一个事件,例如定个时间提醒第二天能够按时起床。定时器有硬件定时器和软件定时器之分:

  • 硬件定时器:是芯片本身提供的定时功能。一般是由外部晶振提供给芯片输入时钟,芯片向软件模块提供一组配置寄存器,接受控制输入,到达设定时间值后芯片中断控制器产生时钟中断。硬件定时器的精度一般很高,可以达到纳秒级别,并且是中断触发方式;
  • 软件定时器:是由操作系统提供的一类系统接口,它构建在硬件定时器基础之上,使系统能够提供不受数目限制的定时器服务。

RT-Thread 的定时器提供两类定时器机制:第一类是单次触发定时器,这类定时器在启动后只会触发一次定时器事件,然后定时器自动停止。第二类是周期触发定时器,这类定时器会周期性的触发定时器事件,直到用户手动的停止,否则将永远持续执行下去。

另外,根据超时函数执行时所处的上下文环境,RT-Thread 的定时器可以分为 HARD_TIMER 模式与 SOFT_TIMER 模式,如下图:
RT-Thread定时器模式

  • HARD_TIMER 模式:定时器超时函数在中断上下文环境中执行(执行时间应该尽量短,执行时不应导致当前上下文挂起、等待),可以在初始化 / 创建定时器时使用参数 RT_TIMER_FLAG_HARD_TIMER 来指定,也是RT-Thread 定时器默认的方式;
  • SOFT_TIMER 模式:通过宏定义 RT_USING_TIMER_SOFT 来决定是否启用该模式。该模式被启用后,系统会在初始化时创建一个 timer 线程,然后 SOFT_TIMER 模式的定时器超时函数在都会在 timer 线程的上下文环境中执行。可以在初始化 / 创建定时器时使用参数 RT_TIMER_FLAG_SOFT_TIMER 来指定设置 SOFT_TIMER 模式。

在 RT-Thread 操作系统中,定时器控制块由结构体 struct rt_timer 定义并形成定时器内核对象,再链接到内核对象容器中进行管理。它是操作系统用于管理定时器的一个数据结构,会存储定时器的一些信息,例如初始节拍数,超时时的节拍数,也包含定时器与定时器之间连接用的链表结构,超时回调函数等。rt_timer的数据结构定义如下:

// rt-thread-4.0.1\include\rtdef.h

/**
 * timer structure
 */
struct rt_timer
{
   
    struct rt_object parent;                            /**< inherit from rt_object */

    rt_list_t        row[RT_TIMER_SKIP_LIST_LEVEL];

    void (*timeout_func)(void *parameter);              /**< timeout function */
    void            *parameter;                         /**< timeout function's parameter */

    rt_tick_t        init_tick;                         /**< timer timeout tick */
    rt_tick_t        timeout_tick;                      /**< timeout tick */
};
typedef struct rt_timer *rt_timer_t;

/**
 * clock & timer macros
 */
#define RT_TIMER_FLAG_DEACTIVATED       0x0             /**< timer is deactive */
#define RT_TIMER_FLAG_ACTIVATED         0x1             /**< timer is active */
#define RT_TIMER_FLAG_ONE_SHOT          0x0             /**< one shot timer */
#define RT_TIMER_FLAG_PERIODIC          0x2             /**< periodic timer */

#define RT_TIMER_FLAG_HARD_TIMER        0x0             /**< hard timer,the timer's callback function will be called in tick isr. */
#define RT_TIMER_FLAG_SOFT_TIMER        0x4             /**< soft timer,the timer's callback function will be called in timer thread. */

#ifndef RT_TIMER_SKIP_LIST_LEVEL
#define RT_TIMER_SKIP_LIST_LEVEL          1
#endif

// rt-thread-4.0.1\src\timer.c
/* hard timer list */
static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
/* soft timer list */
static rt_list_t rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL];

结构体rt_timer的第一个成员即是前面介绍过的抽象内核对象结构rt_object,此时rt_timer.parent.type为RT_Object_Class_Timer,rt_timer.parent.list以双向链表形式保存了所有初始化或创建的定时器对象,rt_timer.parent.flag则用以标识前面介绍过的定时器工作模式,现根据宏定义汇总如下表所示:

flag位 0 1 备注
bit0 RT_TIMER_FLAG_DEACTIVATED:定时器未激活,即初始化值 RT_TIMER_FLAG_ACTIVATED:定时器激活,当定时器start后将会置为此状态 激活/非激活状态
bit1 RT_TIMER_FLAG_ONE_SHOT:单次触发定时器,即定时器时间一到自动失效 RT_TIMER_FLAG_PERIODIC:周期触发定时器,即时间一到自动开始下一次定时 单次定时器/周期定时器
bit2 RT_TIMER_FLAG_HARD_TIMER:HARD_TIMER模式,即在中断环境中执行超时函数 RT_TIMER_FLAG_SOFT_TIMER:SOFT_TIMER模式,即在线程环境中执行超时函数 硬件时钟/软件时钟标志

看完了定时器rt_timer继承的抽象对象rt_object此时各成员的含义,下面看定时器rt_timer私有扩展成员的含义。

rt_list_t类型的row[RT_TIMER_SKIP_LIST_LEVEL]算是一个结构体数组,看到这里可能会疑惑,rt_list_t本身已经是一个双向链表结构,怎么还以数组形式出现呢?我们先看看这

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流云IoT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值