2011-07-25 50 views
8

我需要在信號處理程序(無論是否帶有SA_RESTART)可能會中斷close的條件下調查/測試Linux上某些代碼的行爲。什麼是最方便的設置,可以讓系統調用睡眠一段可測量的時間窗口,在此期間我可以嘗試用信號來觸發過程?一些想法:試圖在Linux上關閉睡眠

  • 故意慢/無響應的NFS掛載
  • 定製FUSE驅動

但由於這些都是一個痛苦位設置的,我想知道如果有什麼更多的關我可以使用可以提供所需行爲的貨架。

+0

在http://stackoverflow.com/questions/40257564/posix-unix-how-to-reliably-close-a-file-descriptor中的代碼示例鏈接中存在對您的問題的回答。這個例子要求你故意中斷一個TCP連接,這樣數據包就會被丟棄。 close()可以通過這種方式阻止分鐘。 –

回答

8

如果沒有其他人有更好的主意...

你可以實現自己的字符設備驅動程序。從Linux Device Drivers (3rd edition)的第3章中的模板開始,調整它在close()上除了block之外什麼也不做。 (你可以使用第7章中的msleepmsleep_interruptible來進行阻塞。)

實際上,如果沒有其他人提出其他建議,我可以通過調整現有代碼來快速調整它。你多久需要它?

[編輯]

OK,試試這個...

的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) "[email protected]" 

.PHONY: default 
endif 

closer.c:

#include <linux/init.h> 
#include <linux/module.h> 
#include <linux/miscdevice.h> 
#include <linux/delay.h> 
#include <linux/fs.h> 

MODULE_DESCRIPTION("Block-on-close driver"); 
MODULE_AUTHOR("Nemo <[email protected]>"); 
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); 

負載使用「insmod的接近模塊。 ○」。如果你有一個合理的現代/完整的Linux環境,udev會自動喚醒併產生/ dev/close。如果沒有,你可以自己創建的設備節點:

mknod /dev/closer c `tr : ' ' </sys/class/misc/closer/dev` 

(也就是說,/ SYS /類/其它/接近的/ dev表示主:未成年人使用)

讀,喜歡寫工作的/ dev/null的;即任何讀取時的EOF,任何寫入都成功。

我已經驗證了「cat </dev/closer」在close()中阻塞了10秒。我還沒有創建一個測試,以捕獲SIGINT(或其他),並驗證它實際上導致EINTR

針對2.6.32內核構建。讓我知道它是如何爲你工作的。

+0

這不是一個匆忙;與此同時,我還有許多其他工作可以完成。 –

+0

+1在x86_64 2.6.38,Ubuntu 11.04上進行了驗證。 (儘管無論出於何種原因,Makefile對我來說只是'/ tmp',所以我只是手工運行'make -C/lib/modules/$(uname -r)/ build M = $(pwd)' ) – user786653

+0

謝謝!不知何故,我錯過了檢查,直到現在。相當奇怪的行爲:當close被信號中斷時,它只返回0(成功)... –