测试Cgroup下的FROZEN(冻住)/THAWED(解冻)对wait_event_interruptible()的影响

本文详细探讨了在Centos7系统上,Kernel5.4.24环境下,FROZEN/THAWED状态如何影响字符设备驱动的wait_event_interruptible函数。通过实例驱动(testdrv.c)和测试应用(test.c),观察到FROZEN和THAWED状态切换对程序运行的影响,得出结论:状态变化不影响该函数的唤醒行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


NOTE:测试环境------Centos7,Kernel 5.4.24的x86 PC机上


一、带有等待队列的字符设备驱动(testdrv.c)

#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/wait.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>

#define TESTMEM_SIZE 0x400
#define TESTMEM_MAJOR 100

static int testmem_major = TESTMEM_MAJOR; 
//设备号
static dev_t devno = {0};

/*test设备结构体*/
struct TestDev {
	struct cdev cdev;
	unsigned char mem[TESTMEM_SIZE];
	wait_queue_head_t	waitq;	
	unsigned int flag;	
};
/*全局gcd*/ 
struct TestDev *gcd;
/*设备类*/
struct class  *cls;

static ssize_t test_write(struct file *file, const char __user *buffer,
			   size_t count, loff_t *ppos)
{
	struct TestDev *dev = file->private_data;
	
	if(copy_from_user(&dev->mem, buffer,sizeof(int)))
        {
       		printk("copy from user failed\n");
        	return -EFAULT;
        }

        wake_up_interruptible(&dev->waitq);
        dev->flag = 1;
        return sizeof(int);

}

static ssize_t test_read(struct file *file, char __user *buffer, size_t count,
			  loff_t *ppos)
{
	struct TestDev *dev = file->private_data;

	wait_event_interruptible(dev->waitq, dev->flag != 0);

   	if(copy_to_user(buffer,&dev->mem,sizeof(int)))
   	{
	  	 printk("copy to user failed\n");
	  	 return -EFAULT;
   	}
   
	dev->flag = 0;

   	return sizeof(int);
}

static int test_open(struct inode *inode, struct file *file)
{
	struct TestDev *cd;
	printk("testmem open success!\n");

	cd  = container_of(inode->i_cdev, struct TestDev, cdev);
    file->private_data = cd;
	
	return 0;
}

static int test_release(struct inode *inode, struct file *filp)
{
    return 0;
}

static const struct file_operations test_fops = {
	.owner		= THIS_MODULE,
	.open		= test_open,
	.read		= test_read,
	.write		= test_write,
	.release    = test_release,
};


static int __init test_init(void)
{
	int ret;
	struct device *device;
	int err;
	
	/*动态申请内存*/
	gcd = kzalloc(sizeof(struct TestDev), GFP_KERNEL);
	if(!gcd){
		goto out;
		return -ENOMEM;
	}
	/*设备号*/
	devno = MKDEV(testmem_major, 0);

	if (testmem_major)
		ret = register_chrdev_region(devno, 1, "testmem");
	else {
		ret = alloc_chrdev_region(&devno, 0, 1, "testmem");
		testmem_major = MAJOR(devno);
	}
	if (ret < 0){
		printk("Fail to register_chrdev_region\n");
		goto err_register_chrdev_region;
	}

	/*创建设备类*/
	cls = class_create(THIS_MODULE, "testmem");
    	if(IS_ERR(cls)){
        	ret = PTR_ERR(cls);
        	goto err_class_create;
   	 }	
	
	/*cdev的初始化和添加*/
	cdev_init(&gcd->cdev, &test_fops);
	gcd->flag = 0;
	err = cdev_add(&gcd->cdev, devno, 1);
	if (err){
		printk(KERN_NOTICE "Error %d adding testmem", err);	
		goto  err_cdev_add;
	}

	/*导出设备信息到用户空间(/sys/class/类名/设备名)*/
	 device = device_create(cls, NULL, devno, NULL, "testmem");
	 if(IS_ERR(device)){
		 ret = PTR_ERR(device);
		 printk("Fail to device_create\n");
	         goto err_device_create; 
	 }
	 printk("Register testmem to system,ok!\n");

	/*初始化等待队列头*/
	init_waitqueue_head(&gcd->waitq);

	return 0;

out:
	kfree(gcd);

err_device_create:
    cdev_del(&gcd->cdev);

err_cdev_add:
    class_destroy(cls);

err_class_create:
    unregister_chrdev_region(devno, 1);

err_register_chrdev_region:
    return ret;

}

static void __exit test_exit(void)
{
	kfree(gcd);

	/*删除sysfs文件系统中的设备*/
    device_destroy(cls, devno);   

    /*删除系统中的设备类*/
    class_destroy(cls);

	cdev_del(&gcd->cdev);

	unregister_chrdev_region(MKDEV(testmem_major, 0), 1);
}

module_init(test_init);
module_exit(test_exit);

MODULE_LICENSE("GPL");
 1. 将写好的驱动文件testdrv.c放到内核源码目录/lib/modules/5.4.24/source/drivers/char/文件夹下;
 2. 在该文件夹下的Makefile中添加指令将该驱动编译为模块;
 		obj-m += testdrv.o
 3. 返回内核源码根目录(/lib/modules/5.4.24/source/),编译后,得到testdrv.ko文件;
 		cd ../../ 		
		make

二、应用程序(test.c)

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

int main(int argc, char **argv)
{
    int fd;
    //char write_buf[255] = { 0 };
    char read_buf[255]  = { 0 };

    fd = open("/dev/testmem", O_RDWR);  
    if (fd < 0)
    {
        printf("can't open!\n");
    }

    printf("hello word fd=%d\n",fd);

    while(1)
    {
		printf("Start reading ...\n");
    	read(fd, read_buf, sizeof(read_buf));
    	printf("%s\n", read_buf);

//		write(fd, write_buf, sizeof(write_buf));
//    	printf("Read %d bytes data from /dev/testmem \n", sizeof(write_buf));

    }

    close(fd);
    return 0;

}
gcc -o test test.c		/*生成测试程序test*/

三、FROZEN/THAWED测试

1)加载驱动;
	insmod testdrv.ko
2)运行测试程序;
	./test
3)查看test的PID;
	ps -a
4)冻住/解冻进程;
	cd /sys/fs/cgroup/freezer/
	mkdir test
	cd test
	cat tasks
	echo PID > tasks
	echo FROZEN > freezer.state			/*冻住*/
	echo THAWED > freezer.state			/*解冻*/FROZENTHAWED的切换时,观察test程序运行的情况。

观察及结论

FROZENTHAWED的切换时,观察test程序运行的情况。

结论:

FROZENT(冻住)/HAWED(解冻)不会给wait_event_interruptible()发信号唤醒等待队列(即不会影响改变其等待队列的状态)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值