RT-Linux的核心可抢占机制
RT-linux是一个可加载的核心模块。在实现上,RT-Linux是通过在Linux核心和中断处理器之间设计一个仿真软件。事实中断不经过中断仿真器,标准Linux的所有中断首先被中断仿真器捕获,所以根本无法影响实时进程的处理。当实时内核禁止中断时,仿真器中一个标志位置位0。当其他非实时中断产生时,仿真器检查标志位,如果为0,说明不允许中断,否则可以立即执行。就是说,Linux不能中断自身,但是RT-Linux可以中断Linux。
RT的调度策略:
1)基于优先级的抢占式调度算法
2)EDF算法
对周期性任务采用单调率调度算法,周期短的任务获得较高优先级,LInux被视为优先级最低的实时任务。
如果发现一个实时系统比普通的操作系统“慢”,我们不必感到奇怪。 有时候,为了获得可预测的行为,甚至需要禁止使用Cache, 这会带来一些性能上的丢失。对一个实时系统来说, 处理器Cache所提供的管道线单元和预言跳转算法是最大的敌人。
HOWTO:
1)下载内核,kernel.org
2)下载内核版本对应的rt patch,kernel.org, 现在5.6内核有的
3)解压源码
4)patch -p1 < patchfile
5)使能CONFIG_PREEMPT_RT_FULL, 关闭debugging机制,比如lock debugging
6)编译内核
HOWTO建立一个实时应用
1)调度和优先级 Scheduling and priority
sched_setscheduler()
pthread_attr_setschedpolicy
2)内存加锁
mlock(addr, length) - 只针对addr开始length的内存
mlockall() - 针对整个程序,不论是不是实时线程
内存加锁,在内存分配后就立即做虚拟地址到物理空间的映射,而且这个映射保持不动,也不被换出。这是避免在后面出现page fault
3)通过线程属性设置栈大小
mlockall()也会把stack钉在位置(保持虚拟到物理的映射),不会出现pagefault,所以尽量是栈够用就行,设定栈大小,可以支持更多的实时线程。pthread_attr_setstacksize()
4)避免在实时线程中使用动态分配,尽量再进入实时线程前完成动态内存分配,由于mlockall作用,会立即触发缺页异常。
/*
* POSIX Real Time Example
* using a single pthread as RT thread
*/
#include
#include
#include
#include
#include
#include
void *thread_func(void *data)
{
/* Do RT specific stuff here */
return NULL;
}
int main(int argc, char* argv[])
{
struct sched_param param;
pthread_attr_t attr;
pthread_t thread;
int ret;
/* Lock memory */
if(mlockall(MCL_CURRENT|MCL_FUTURE) == -1) {
printf("mlockall failed: %m\n");
exit(-2);
}
/* Initialize pthread attributes (default values) */
ret = pthread_attr_init(&attr);
if (ret) {
printf("init pthread attributes failed\n");
goto out;
}
/* Set a specific stack size */
ret = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
if (ret) {
printf("pthread setstacksize failed\n");
goto out;
}
/* Set scheduler policy and priority of pthread */
ret = pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
if (ret) {
printf("pthread setschedpolicy failed\n");
goto out;
}
param.sched_priority = 80;
ret = pthread_attr_setschedparam(&attr, ¶m);
if (ret) {
printf("pthread setschedparam failed\n");
goto out;
}
/* Use scheduling parameters of attr */
ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
if (ret) {
printf("pthread setinheritsched failed\n");
goto out;
}
/* Create a pthread with specified attributes */
ret = pthread_create(&thread, &attr, thread_func, NULL);
if (ret) {
printf("create pthread failed\n");
goto out;
}
/* Join the thread and wait until it is done */
ret = pthread_join(thread, NULL);
if (ret)
printf("join pthread failed: %m\n");
out:
return ret;
}