繁体   English   中英

具有 SCHED_RR 和更高实时优先级的 pthread 无法抢占 kernel 模块中具有更低优先级的 kthread

[英]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++ 标签。

实验准备:

  1. Ubuntu 18.04。 (我假设它在正常 linux 和 RT linux 上都是可行的)

  2. kthread 是用SCHED_RR和 rt 优先级 50 创建的。

    • kthread 只是一个带有udelay()的无限循环,它不应该禁用抢占。
    • kthread 在调用udelay之前会检查kthread_should_stop()
  3. pthread 是使用SCHED_RR和 rt 优先级 70 创建的。

    • pthread 是一个繁忙的无限循环
    • 用户程序创建的pthread会调用pthread_join等待直到pthread结束 ctrl+c
    while( true ){
        sleep( 1 );
        std:: cout << "wake\n";
    }

结果

如果kthread先运行,而 userprogram 会在pthread_join调用后卡住。 Output 在 kernel 模块移除之前无法接收到来自pthread的字符串(调用 kthread 停止)。

我的假设是 pthread 永远不会启动,因为控制台上没有打印 output。 但我不确定这个假设是否正确。

参考

重现实验的代码

====这是带有测试代码的文字墙====

kthread.c - 一个 kernel 模块


#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, &param );
    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);

Makefile 用于 kthread.c


#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

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM