Linux 内核中的强制抢占

问题描述 投票:0回答:1

我玩过内核抢占。 想法是看看较高优先级 RT 进程如何抢占内核中运行的较低优先级进程。 为了进入内核,使用

read()
系统调用回调创建了简单的模块:

#include <linux/cdev.h>

#include <linux/delay.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/sched.h>


#include <linux/module.h>       /* Needed by all modules */
#include <linux/kernel.h>       /* Needed for KERN_INFO */
#include <linux/init.h>         /* Needed for the macros */


static dev_t my_dev;
static struct cdev *my_cdev;

// sysfs class structure
static struct class *mychardev_class = NULL;

// callback for read() system call
static ssize_t my_read(struct file *file, char __user *buf,size_t count,loff_t *ppos)
{
    int len = 20;
    if(*ppos > 0)
    {
        return 0;
    }
    msleep(10000);
    if (copy_to_user(buf, "hello from demo_dev ", len)) {
        return -EFAULT;
    } else {
        *ppos +=len;
        return len;
    }
}


static struct file_operations my_fops =
{
    .owner = THIS_MODULE,
    .read = my_read,
};




static int __init hello_init (void)
{

    my_dev = MKDEV(400,0);
    
    // create sysfs class
    mychardev_class = class_create(THIS_MODULE, "mychardev");
    
    register_chrdev_region(my_dev,1,"demo");

    my_cdev=cdev_alloc();
    if(!my_cdev)
    {
        printk (KERN_ERR "cdev alloc error.\n");
        return -1;      
    }
    
    my_cdev->ops = &my_fops;
    my_cdev->owner = THIS_MODULE;
    
    cdev_init(my_cdev, &my_fops);
    
    if(cdev_add(my_cdev,my_dev,1))
    {
        printk (KERN_ERR "cdev add error.\n");
        return -1;      
    }

    // create device node /dev/demo_dev
    device_create(mychardev_class, NULL, my_dev, NULL, "demo_dev");
        
    printk (KERN_INFO "demo_dev added.\n");
    return 0;

}


static void __exit hello_exit (void)
{
    
    device_destroy(mychardev_class, my_dev);
    cdev_del(my_cdev);
    
    class_unregister(mychardev_class);
    class_destroy(mychardev_class);
    
    unregister_chrdev_region(my_dev, 1);
    printk (KERN_INFO "demo_dev removed.\n");
}


module_init (hello_init);
module_exit (hello_exit);
MODULE_LICENSE("GPL");

为了测试它,使用

SCHED_FIFO
策略创建了 2 个线程,一个具有较高优先级 50,一个具有较低优先级 30,2 秒后创建:

#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


int off;

void *hi_prio(void *p)
{
    printf("thread1 start time=%ld\n",time(NULL)-off);
    sleep(3);
    printf("thread1 stop time=%ld\n",time(NULL)-off);
    return NULL;
}

void *low_prio(void *p)
{
    int ret;
    char buf[20];
    int fd=open("/dev/demo_dev",O_RDONLY);  // #mknod /dev/demo c 400 0
    printf("thread2 start time=%ld\n",time(NULL)-off);
    ret = read(fd,buf,20);
    printf("thread2 read:%s\n");
    printf("thread2 stop time=%ld\n",time(NULL)-off);
    return NULL;
}

int main()
{
    pthread_t t1,t2,t3;
    
    pthread_attr_t attr;
    
    struct sched_param param;
      
    pthread_attr_init(&attr);
    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
    
    param.sched_priority = 50;
    pthread_attr_setschedparam(&attr, &param);
    
    off = time(NULL);
    
    pthread_create(&t1,&attr,hi_prio,NULL);
    
    param.sched_priority = 30;
    pthread_attr_setschedparam(&attr, &param);
    
    sleep(2);
    pthread_create(&t2,&attr,low_prio,NULL);
    
    sleep(20);
    printf("main thread stop time=%ld\n",time(NULL)-off);
    puts("end test");
    return 0;
}

高优先级线程休眠了3秒,结果符合预期:

thread1 start time=0
thread2 start time=2
thread1 stop time=3
thread2 read:hello from demo_dev
thread2 stop time=13
main thread stop time=22
end test

但是当我改变困倦等待

msleep(10000);
忙碌等待时:

    mdelay(5000); // busy-wait for 5 seconds
    schedule();
    mdelay(5000); // busy-wait for 5 seconds

高优先级线程在7秒后唤醒。

thread1 start time=0
thread2 start time=2
thread1 stop time=7
thread2 read:hello from demo_dev
thread2 stop time=12
main thread stop time=22
end test

我想原因是因为只配置了自愿抢占:

CONFIG_PREEMPT_VOLUNTARY=y
#CONFIG_PREEMPT is not set

进程不能在内核代码中被抢占,除非它显式调用

schedule()
或阻塞(睡眠)? 我假设其他调度策略会产生相同的结果?

linux kernel preemption
1个回答
1
投票

您只启用了自愿抢占,

CONFIG_PREEMPT is not set
,这意味着当内核执行时
syscall
当它变得可运行时,另一个更高优先级的进程无法在同一个CPU上中断它。

© www.soinside.com 2019 - 2024. All rights reserved.