我现在使用嵌入式产品,即 PIC32 Microchip CPU。
我熟悉几个实时内核:AVIX、FreeRTOS、TNKernel,在所有这些内核中,我们几乎都有两个版本的函数:一个用于从任务调用,第二个用于从 ISR 调用。
当然,这对于可以切换上下文和/或睡眠的函数是有意义的:显然,ISR 不能睡眠,并且应该以不同的方式进行上下文切换。但是有几个函数既不切换上下文也不休眠:比如说,它可能返回系统滴答计数,或者设置软件计时器等。
现在,我正在实现自己的内核:TNeoKernel,它具有格式良好的代码并经过仔细测试,并且有时我正在考虑发明“通用”函数:可以从任务或 ISR 上下文调用的函数。但是由于所有上述三个内核都使用单独的功能,我担心我会做错什么。
比如说,在任务和 ISR 上下文中,TNKernel 使用不同的例程来禁用/恢复中断,但据我所知,唯一可能的区别是,如果目标平台不支持,ISR 函数可能被“编译”作为优化嵌套中断。但是如果目标平台支持嵌套中断,那么禁用/恢复中断对于任务和 ISR 上下文看起来完全一样。
所以,我的问题是:在哪些平台上,从 ISR 禁用/恢复中断的操作应该与非 ISR 上下文不同?
如果没有这样的平台,我更愿意使用“通用”功能。如果您对此方法有任何意见,我们将不胜感激。
UPD:我不喜欢有两组函数,因为它们会导致明显的代码重复和复杂化。说,我需要提供一个应该启动软件定时器的功能。这是它的样子:
enum TN_RCode _tn_timer_start(struct TN_Timer *timer, TN_Timeout timeout)
{
/* ... real job is done here ... */
}
/*
* Function to be called from task
*/
enum TN_RCode tn_timer_start(struct TN_Timer *timer, TN_Timeout timeout)
{
TN_INTSAVE_DATA; //-- define the variable to store interrupt status,
// it is used by TN_INT_DIS_SAVE()
// and TN_INT_RESTORE()
enum TN_RCode rc = TN_RC_OK;
//-- check that function is called from right context
if (!tn_is_task_context()){
rc = TN_RC_WCONTEXT;
goto out;
}
//-- disable interrupts
TN_INT_DIS_SAVE();
//-- perform real job, after all
rc = _tn_timer_start(timer, timeout);
//-- restore interrupts state
TN_INT_RESTORE();
out:
return rc;
}
/*
* Function to be called from ISR
*/
enum TN_RCode tn_timer_istart(struct TN_Timer *timer, TN_Timeout timeout)
{
TN_INTSAVE_DATA_INT; //-- define the variable to store interrupt status,
// it is used by TN_INT_DIS_SAVE()
// and TN_INT_RESTORE()
enum TN_RCode rc = TN_RC_OK;
//-- check that function is called from right context
if (!tn_is_isr_context()){
rc = TN_RC_WCONTEXT;
goto out;
}
//-- disable interrupts
TN_INT_IDIS_SAVE();
//-- perform real job, after all
rc = _tn_timer_start(timer, timeout);
//-- restore interrupts state
TN_INT_IRESTORE();
out:
return rc;
}
因此,对于几乎所有系统功能,我们都需要像上面这样的包装器。对于作为内核开发人员以及内核用户的我来说,这是一种不便。
唯一的区别是使用了不同的宏:对于任务,这些是TN_INTSAVE_DATA
, TN_INT_DIS_SAVE()
, TN_INT_RESTORE()
; 对于中断,这些是TN_INTSAVE_DATA_INT
, TN_INT_IDIS_SAVE()
, TN_INT_IRESTORE()
.
对于支持嵌套中断的平台(ARM、PIC32),这些宏是相同的。对于不支持嵌套中断的其他平台,TN_INTSAVE_DATA_INT
,TN_INT_IDIS_SAVE()
并TN_INT_IRESTORE()
扩展为空。所以有点性能优化,但是在我看来成本太高了:更难维护,用起来不太方便,而且代码量变大了。