[英]A pthread with SCHED_RR and higher real time priority failed to preempt a kthread in kernel module with lower priority
我有两个线程:一个 kernel 线程和一个用户空间pthread
。 我假设pthread
设置为SCHED_RR
具有更高的 rt 优先级应该抢占具有kthread
和更低优先级的SCHED_RR
,同时它们都运行一个相同的 cpu。
但是我的测试失败了。 kthread
一直在运行,而 pthread 没有进展。
注意:我为这篇文章添加了 C 和 C++ 标签,因为我的例子是一个带有 C++ 和一个带有 C 的标签。如果有任何标签适合这篇文章,请编辑它并删除 C 和 C++ 标签。
Ubuntu 18.04。 (我假设它在正常 linux 和 RT linux 上都是可行的)
kthread 是用SCHED_RR
和 rt 优先级 50 创建的。
udelay()
的无限循环,它不应该禁用抢占。udelay
之前会检查kthread_should_stop()
pthread 是使用SCHED_RR
和 rt 优先级 70 创建的。
pthread
会调用pthread_join
等待直到pthread
结束 ctrl+c while( true ){
sleep( 1 );
std:: cout << "wake\n";
}
如果kthread
先运行,而 userprogram 会在pthread_join
调用后卡住。 Output 在 kernel 模块移除之前无法接收到来自pthread
的字符串(调用 kthread 停止)。
我的假设是 pthread 永远不会启动,因为控制台上没有打印 output。 但我不确定这个假设是否正确。
pthread 无法抢占 kthread
非 RT Linux kernel 上的 FIFO/RR 调度程序有多“实时”?
====这是带有测试代码的文字墙====
#include <uapi/linux/sched/types.h> // For sched_param
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kthread.h> // kthread_create(), kthread_should_stop(), kthread_stop()
#include <linux/delay.h> // msleep()
#include <linux/sched.h> // For struct sched_param, sched_setcheduler()
#define MY_THREADNAME "kthread example"
#define MY_MODULENAME "kthread occupy cpu1 module"
#pragma GCC diagnostic ignored "-Wdeclaration-after-statement" // Ignore C90 declaration convention since gcc has extension for it.
MODULE_LICENSE( "GPL v2" );
MODULE_AUTHOR( "TEST" );
MODULE_DESCRIPTION( MY_MODULENAME );
struct task_struct *m_task1;
static int m_t1id = 1;
int thread_fn(void *data)
{
int id = *((int*)data);
int ret = 0;
int cpu = -1;
cpu = get_cpu();
put_cpu();
pr_info( "IN THREAD FUNCTION %d, CPU is %d \n", id, cpu);
while(!kthread_should_stop()){
// try to busy blocking cpu, but udelay doesn't disable preemption.
udelay(1000);
}
pr_info( "EXIT from thread function 1\n");
return 0;
}
static int __init init_my_module(void) {
pr_info( "Hello, %s!\n", MY_MODULENAME );
// Get cpu will disable preemption, so must put_cpu to enable preemption
int cpu = get_cpu();
put_cpu();
pr_info( "Current cpu for initializing is %d\n", cpu );
pr_info( "Current pid is %d\n", current->pid );
// threadfn, data, and printf-style name. Created thread would be suspended, need to wake up.
m_task1 = kthread_create(&thread_fn,(void *)&m_t1id,"testing kt%d",m_t1id);
pr_info( "T1 pid is %d", m_task1->pid );
kthread_bind(m_task1,1 );
// Set Realtime priority
struct sched_param param = {50};
sched_setscheduler( m_task1, SCHED_RR, ¶m );
pr_info( "T1 effective prio AFTER set policy= %d", m_task1->prio );
wake_up_process(m_task1);
return 0;
}
static void __exit exit_my_module(void) {
kthread_stop( m_task1 );
pr_info( "Bye, %s!\n", MY_MODULENAME );
}
module_init( init_my_module);
module_exit( exit_my_module);
#Test on local ubuntu
KVERSION := $(shell uname -r)
KERNEL_DIR = /lib/modules/$(KVERSION)/build
PWD := $(shell pwd)
MODULE_NAME = kthread
obj-m = $(MODULE_NAME).o
all:
make -C $(KERNEL_DIR) M=$(PWD) modules
clean:
make -C $(KERNEL_DIR) M=$(PWD) clean
pthread.cpp 的编译命令行是g++ pthread.cpp -pthread
#include <pthread.h>
#include <sched.h>
#include <iostream>
#include <sys/resource.h> // to use getrusage
#include <unistd.h>
void* helloworld ( void *arg ){
int cpuid = sched_getcpu();
int sum = 0;
std::cout<< "Hello pthread on cpu " << cpuid << std::endl;
pthread_t pself = pthread_self();
int policy = 0;
struct sched_param sparam;
pthread_getschedparam( pself, &policy, &sparam );
std::cout << "Current thread Policy: " << policy << " prio:" << sparam.sched_priority << "\n";
int err = pthread_setschedprio( pself, 99 );
std::cout<< "set prio ret:"<< err <<"\n";
// keep sleep to check process priority
while( true ){
sleep( 1 );
std:: cout << "wake\n";
}
return NULL;
}
int main(void){
std::cout<<" pthread create\n";
pthread_t handle;
pthread_attr_t attr;
cpu_set_t cpus;
struct sched_param sparam;
int error = 0;
// Setting SCHED_FIFO must run program in sudo
int policy = SCHED_RR;
CPU_ZERO( &cpus );
// Set bit cpu0 to enable in mask.
CPU_SET( 1, &cpus );
pthread_attr_init( &attr );
// Let pthread using specified attribute explicitly
error = pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
std::cout << "set inherit sched result: "<< error << "\n";
error = pthread_attr_setschedpolicy( &attr, policy );
std::cout << "set policy result: "<< error << "\n";
// _np means "non-portable"
pthread_attr_setaffinity_np( &attr,sizeof(cpu_set_t), &cpus );
// Set priority
int max = 70;//sched_get_priority_max(policy);
sparam.sched_priority = max;// ( 4* min + 6*max )/10;
std::cout << "Set priority: " << sparam.sched_priority << "\n";
error = pthread_attr_setschedparam(&attr ,&sparam);
std::cout << "setschedparam: " << error << std::endl;
// before create thread, raise main thread as higher priority
error = pthread_setschedparam(pthread_self(), policy, &sparam);
std::cout<< "main thread set prio " << error << std::endl;
error = pthread_create( &handle, &attr , &helloworld, NULL );
std::cout<< "pthread_create " << error << std::endl;
void* retvalue;
pthread_join( handle, &retvalue );
pthread_attr_destroy( &attr );
return 0;
}
简短的回答:需要启用CONFIG_PREEMPT
。
我试过 CONFIG_PREEMPT linux 并且 pthread 确实抢占了具有更高优先级的 kernel 线程。
如果您有兴趣构建 kernel,以下链接适用于 ubuntu 18.04。
我选择了我自己的问题,但不会接受它,因为它只是经过测试的行为,而不是为什么。 我想收到一个解释CONFIG_PREEPT
的答案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.