Trying to make close sleep on Linux

前端 未结 1 1372
情歌与酒
情歌与酒 2021-01-02 05:48

I need to investigate/test the behavior of some code on Linux under conditions where close might be interrupted by signal handlers (either with or without

1条回答
  •  走了就别回头了
    2021-01-02 06:44

    If nobody else has a better idea...

    You could implement your own character device driver. Start with the template from Chapter 3 in Linux Device Drivers (3rd edition), and tweak it to do nothing except block for a while on close(). (You can use msleep or msleep_interruptible from Chapter 7 to do the blocking.)

    Actually, if nobody else suggests something else, I can probably whip this up pretty quickly by adapting some existing code I have. How soon do you need it?

    [edit]

    OK, try this...

    Makefile:

    ifneq ($(KERNELRELEASE),)
            obj-m := closer.o
    
    else
            KERNELDIR ?= /lib/modules/$(shell uname -r)/build
            PWD := $(shell pwd)
    
    default: modules
    
    %:
            $(MAKE) -C $(KERNELDIR) M=$(PWD) "$@"
    
    .PHONY: default
    endif
    

    closer.c:

    #include 
    #include 
    #include 
    #include 
    #include 
    
    MODULE_DESCRIPTION("Block-on-close driver");
    MODULE_AUTHOR("Nemo ");
    MODULE_LICENSE("GPL");
    #define VERSION "20110705"
    MODULE_VERSION(VERSION);
    
    #define MY_NAME "closer"
    
    int my_open(struct inode *, struct file *);
    int my_release(struct inode *, struct file *);
    ssize_t my_read(struct file *, char __user *, size_t, loff_t *);
    ssize_t my_write(struct file *, const char __user *, size_t, loff_t *);
    
    static struct file_operations my_fops = {
        .owner = THIS_MODULE,
        .open = my_open,
        .read = my_read,
        .write = my_write,
        .release = my_release,
    };
    
    static struct miscdevice my_dev;
    
    int __init
    my_init(void)
    {
        int err = 0;
    
        printk(KERN_INFO "%s: loading version %s\n", MY_NAME, VERSION);
    
        my_dev.minor = MISC_DYNAMIC_MINOR;
        my_dev.name = MY_NAME;
        my_dev.fops = &my_fops;
        err = misc_register(&my_dev);
    
        if (err)
            printk(KERN_ERR "%s: misc_register failed, error %d\n", MY_NAME, err);
    
        return err;
    }
    
    int
    my_open(struct inode *inode, struct file *filp)
    {
        return 0;
    }
    
    ssize_t
    my_read(struct file *file, char __user *p, size_t n, loff_t *off) {
        return 0;
    }
    
    ssize_t
    my_write(struct file *file, const char __user *p, size_t n, loff_t *off) {
        return n;
    }
    
    int
    my_release(struct inode *inode, struct file *filp)
    {
        int err = 0;
        /* 10 second sleep, interruptible. */
        if (msleep_interruptible(10 * 1000) > 0)
            err = -EINTR;
    
        return err;
    }
    
    void __exit
    my_exit(void)
    {
        misc_deregister(&my_dev);
        printk(KERN_INFO "%s: unloaded\n", MY_NAME);
    }
    
    module_init(my_init);
    module_exit(my_exit);
    

    Load the module using "insmod closer.o". If you have a reasonably modern/complete Linux environment, udev will wake up and generate /dev/closer automatically. If not, you can create the device node yourself:

    mknod /dev/closer c `tr : ' ' 

    (That is, /sys/class/misc/closer/dev indicates the major:minor to use.)

    Reads and writes work like /dev/null; i.e., EOF on any read, success on any write.

    I have verified that "cat < /dev/closer" blocks in close() for 10 seconds. I have not created a test to catch SIGINT (or whatever) and verify that it actually results in EINTR.

    Built against a 2.6.32 kernel. Let me know how it works for you.

    0 讨论(0)
提交回复
热议问题