【问题标题】:A pthread with SCHED_RR and higher real time priority failed to preempt a kthread in kernel module with lower priority具有 SCHED_RR 和更高实时优先级的 pthread 无法抢占内核模块中具有更低优先级的 kthread
【发布时间】:2021-02-25 03:02:53
【问题描述】:

前言:

我有两个线程一个内核线程和一个用户空间pthread。我假设pthread 设置为SCHED_RR 具有更高的rt 优先级应该抢占kthreadSCHED_RR 和更低的优先级。

我假设在 SCHED_RR 中具有足够高的优先级,pthread 可以抢占任何具有较低优先级的线程。但是我的测试失败了。 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 先运行,用户程序会在pthread_join 调用后卡住。 pthread 的输出字符串在内核模块被移除之前无法接收(调用 kthread 停止)。

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

参考

重现实验的代码

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

kthread.c - 内核模块


#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);

kthread.c 的 Makefile


#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;
}

【问题讨论】:

    标签: c++ linux linux-kernel pthreads scheduling


    【解决方案1】:

    简短的回答:CONFIG_PREEMPT enabled 是必需的。

    我在 CONFIG_PREEMPT linux 上试过,pthread 确实抢占了具有更高优先级的内核线程。

    如果您有兴趣构建内核,以下链接适用于 ubuntu 18.04。

    我选择了我自己的问题,但不会接受它,因为这只是经过测试的行为,而不是为什么。我想收到解释CONFIG_PREEPT的答复。

    【讨论】:

      猜你喜欢
      • 2011-03-13
      • 2011-12-02
      • 2014-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-19
      相关资源
      最近更新 更多