RT-Thread 源码阅读笔记之hook function call macro
RT-Thread 源码阅读笔记之hook function call macro
RT-Thread 操作系统
hook function call macro
The hook function call macro 可能是指在某些编程语言中用于插入或修改函数调用行为的宏。这种宏通常用于调试、性能监控、日志记录或其他需要在函数执行前后进行额外操作的场景。例如:
#define HOOK_CALL(func) \
do { \
if (hook_##func != NULL) { \
hook_##func(); \
} \
} while (0)
/* 使用时 */
void foo() {
do_something();
HOOK_CALL(foo);
do_other_things();
}
在rtt中,对hook的宏定义是这样的:
/**
* The hook function call macro
*/
#define _RT_OBJECT_HOOK_CALL(func, argv) __ON_HOOK_ARGS(func, argv)
#define RT_OBJECT_HOOK_CALL(func, argv) _RT_OBJECT_HOOK_CALL(func, argv)
#ifdef RT_HOOK_USING_FUNC_PTR
#define __ON_HOOK_ARGS(__hook, argv) do {if ((__hook) != RT_NULL) __hook argv; } while (0)
#else
#define __ON_HOOK_ARGS(__hook, argv)
#endif /* RT_HOOK_USING_FUNC_PTR */
/* 在使用时 (src/clock.c)*/
static void (*rt_tick_hook)(void);
/* This function will set a hook function, which will be invoked when tick increase */
void rt_tick_sethook(void (*hook)(void))
{
rt_tick_hook = hook;
}
void rt_tick_increase(void)
{
RT_ASSERT(rt_interrupt_get_nest() > 0);
RT_OBJECT_HOOK_CALL(rt_tick_hook, ());
/* tracing cpu usage */
_update_process_times(1);
// any code ......
}
在上面的例子里,注册了一个时间片增长的钩子函数 rt_tick_hook,并且在 rt_tick_increase() 运行时被调用,rt_tick_increase() 给操作系统提供时钟,stm32一般在滴答定时器中被调用,所以每次进入滴答定时器中断,都会触发钩子函数rt_tick_hook,简单来说,就是可以跟随时间片增长函数进行周期执行。
在rtt的历程中,我找到了相关的运用:
#define PWM_CYCLE_MAX 255
static struct rt_device_pwm *pwm_dev; /* rtt pwm设备 */
static void pwm_tick_hook(void)
{
uint32_t pulse;
if (pwm_dev)
{
/* PWM.CH3 duty cycle : 0%->100% for every ~2.5 seconds */
pulse = (rt_tick_get() >> 1) % (PWM_CYCLE_MAX + 1);
pulse = (pwm_period * pulse + PWM_CYCLE_MAX/2) / PWM_CYCLE_MAX;
rt_pwm_set_pulse(pwm_dev, 3, pulse); /* rtt pwm设备的通道3输出占空比为pulse的脉冲 */
}
}
这是一段测试pwm设备的测试程序,意思是在2.5秒内将PWM通道3的占空比从0%线性增加到100%,然后再从100%线性减少到0%,循环反复。至于这个2.5s,就是通过rt_tick_increase()的钩子函数rt_tick_hook来实现周期调用,从而实现2.5s的周期。
总结
在嵌入式实时操作系统(RTOS)中,钩子(hook)函数是一种常见的设计模式,它允许用户在操作系统的特定事件或动作发生时插入自定义的代码。这种机制在RTT中得到了广泛应用,特别是在时钟管理方面。rt_tick_increase()是RTT内核中的一个关键函数,它负责增加系统的滴答计数,通常每秒钟调用多次。这个函数在系统计时、任务切换等方面起着核心作用。
由于clock.c文件属于操作系统内核的一部分,直接修改内核源码是不推荐的,因为这可能会导致系统不稳定,而且对内核的修改在系统升级时可能会丢失。因此,RTT提供了一种钩子机制,允许用户在不改动内核代码的情况下,注册自己的函数来扩展内核功能。
例如,用户可能需要周期性地执行某些操作,比如PWM(脉宽调制)信号的测试。在这种情况下,用户可以注册一个钩子函数,这个钩子函数会在每次rt_tick_increase()被调用时执行。这样,用户就可以在不直接修改rt_tick_increase()的情况下,实现周期性任务的需求。
通过使用钩子函数,RTT提供了一种灵活且安全的机制,使用户能够在保留内核稳定性和可维护性的同时,实现特定的功能扩展。这种设计既保护了内核的完整性,又满足了用户的定制化需求,是一种理想的解决方案。
--- 2025/1/3