模拟处于D状态的不可杀死的进程


14

对于在服务器环境外进行灾难测试的情况,我们正在寻找一种使进程陷入D(不间断睡眠)状态的简便方法。

有什么简单的方法吗?C示例代码示例为加号:)

编辑 -第一个答案是半正确的,因为该过程显示为处于D状态,但它仍接收信号并且可以被杀死



在哪个操作系统上?还是您在寻找一种便携式解决方案(不确定是否有解决方案)?
derobert 2014年

@mr_tron-这不是“不间断的” :)
er453r14年

1
@derobert-很抱歉,不够精确-ubuntu服务器12.04.4
er453r 2014年

1
对于那些正在寻找“有效”解决方案的人,请访问stackoverflow.com/a/22754979/2182622
noname

Answers:


2

我遇到了同样的问题,并通过创建陷入D状态的内核模块解决了该问题。

由于我没有在模块的任何经验,我把代码从这个turorial与发现了一些修改某处esle

结果是/ dev / memory上的设备被卡住,但可以在其上被唤醒(它需要写两次,我不知道为什么,但我不在乎)。

只需使用它:

# make
# make mknod
# make install
# cat /dev/memory   # this gets blocked

要解除阻止,请从另一个终端执行以下操作:

# echo -n a > /dev/memory
# echo -n a > /dev/memory

生成文件:

obj-m += memory.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

install:
    sudo insmod memory.ko

uninstall:
    sudo rmmod memory

mknod:
    sudo mknod /dev/memory c 60 0
    sudo chmod 666 /dev/memory

用于memory.c的代码:

/* Necessary includes for device drivers */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <asm/uaccess.h> /* copy_from/to_user */
#include <linux/sched.h>

MODULE_LICENSE("Dual BSD/GPL");

/* Declaration of memory.c functions */
int memory_open(struct inode *inode, struct file *filp);
int memory_release(struct inode *inode, struct file *filp);
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t memory_write(struct file *filp, char *buf, size_t count, loff_t *f_pos);
void memory_exit(void);
int memory_init(void);

/* Structure that declares the usual file */
/* access functions */
ssize_t memory_write( struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
int memory_open(struct inode *inode, struct file *filp);
int memory_release(struct inode *inode, struct file *filp);
struct file_operations memory_fops = {
    .read = memory_read,
    .write = memory_write,
    .open = memory_open,
    .release = memory_release
};

/* Declaration of the init and exit functions */
module_init(memory_init);
module_exit(memory_exit);

/* Global variables of the driver */
/* Major number */
int memory_major = 60;
/* Buffer to store data */
char *memory_buffer;

int memory_init(void) {
    int result;

    /* Registering device */
    result = register_chrdev(memory_major, "memory", &memory_fops);
    if (result < 0) {
        printk(
                "<1>memory: cannot obtain major number %d\n", memory_major);
        return result;
    }

    /* Allocating memory for the buffer */
    memory_buffer = kmalloc(1, GFP_KERNEL); 
    if (!memory_buffer) { 
        result = -ENOMEM;
        goto fail; 
    } 
    memset(memory_buffer, 0, 1);

    printk("<1>Inserting memory module\n"); 
    return 0;

fail: 
    memory_exit(); 
    return result;
}

void memory_exit(void) {
    /* Freeing the major number */
    unregister_chrdev(memory_major, "memory");

    /* Freeing buffer memory */
    if (memory_buffer) {
        kfree(memory_buffer);
    }

    printk("<1>Removing memory module\n");

}

int memory_open(struct inode *inode, struct file *filp) {

    /* Success */
    return 0;
}

int memory_release(struct inode *inode, struct file *filp) {

    /* Success */
    return 0;
}
static DECLARE_WAIT_QUEUE_HEAD(wq);
static volatile int flag = 0;

ssize_t memory_read(struct file *filp, char *buf, 
        size_t count, loff_t *f_pos) { 

    printk("<1>going to sleep\n");
    flag = 0;
    //wait_event_interruptible(wq, flag != 0);
    wait_event(wq, flag != 0);

    printk("<1>Reading from memory module\n");
    /* Transfering data to user space */ 
    copy_to_user(buf,memory_buffer,1);

    /* Changing reading position as best suits */ 
    if (*f_pos == 0) { 
        *f_pos+=1; 
        return 1; 
    } else { 
        return 0; 
    }
}

ssize_t memory_write( struct file *filp, char *buf,
        size_t count, loff_t *f_pos) {

    char *tmp;

    printk("<1>wake someone up\n");
    flag = 1;
    //wake_up_interruptible(&wq);
    wake_up(&wq);

    printk("<1>Writting to memory module\n");
    tmp=buf+count-1;
    copy_from_user(memory_buffer,tmp,1);
    return 1;
}

不幸的是,两个链接均已失效,并且此处复制的文件不包含所有内容。
杜纳托托托斯

10

来自https://blogs.oracle.com/ksplice/entry/disown_zombie_children_and_the

当一个进程需要等待某种东西(通常是I / O)并且不应该在等待时处理信号时,它会进入不间断的睡眠 (STAT D)状态。这意味着你做不到,因为所有的杀戮都是向它发送信号。如果您在其他计算机具有打开的网络连接的同时拔出NFS服务器的电源,则在现实世界中可能会发生这种情况。kill

我们可以利用vfork系统调用来创建自己的有限时间的不间断进程。vfork就像一样fork,只是地址空间不会从父级复制到子级中,因为预期exec这会丢弃复制的数据。对我们来说很方便,当您vfork的父母不间断地(通过wait_on_completion)等待孩子的exec或时exit

jesstess@aja:~$ cat uninterruptible.c 
int main() {
    vfork();
    sleep(60);
    return 0;
}
jesstess@aja:~$ gcc -o uninterruptible uninterruptible.c
jesstess@aja:~$ echo $$
13291
jesstess@aja:~$ ./uninterruptible
and in another shell:

jesstess@aja:~$ ps -o ppid,pid,stat,cmd $(pgrep -f uninterruptible)

13291  1972 D+   ./uninterruptible
 1972  1973 S+   ./uninterruptible

我们看到孩子(PID 1973, PPID 1972)处于不间断的睡眠状态,而父母(PID 1972, PPID 13291-外壳)处于不间断的睡眠状态,此时它等待60秒。

关于此脚本的一件整洁的事情(恶作剧?)是,不间断睡眠中的进程对计算机的平均负载有所贡献。因此,您可以运行此脚本100次,以暂时为计算机提供平均100的平均负载,如所示uptime


正是在寻找什么!非常感谢你!
er453r 2014年

3
可悲的是,该过程处于D状态,但我可以使用以下命令将其杀死kill:/
er453r 2014年

@ er453r-对不起,伙计。老实说,我对此了解不多-答案只是复制/粘贴,这就是为什么我将其设置为社区Wiki内容的原因。我读了您的问题,对自己感到好奇,然后进行了一次谷歌搜索,然后发现了我认为非常有趣的信息。那就是你在上面看到的。但是选票和其他票数不会增加我自己的声誉,因为它已经维基百科记录,并且因为我偷了它。也许该页面上有更多信息可以解释原因?
mikeserv 2014年

谢谢-正如您发布时一样,我已经阅读过。我已经在互联网上搜索了此文件,但是每个人都试图摆脱这个过程,而不是创建它们:P通常,堆栈交换始终是我的最后选择:)
er453r 2014年

是的,我仍然可以杀掉它:-/
Leo Ufimtsev

2

基本上,你不能。阅读标题为:TASK_KILLABLE的文章:Linux中的新进程状态

摘抄

Linux®内核2.6.25引入了一个新的进程状态,称为TASK_KILLABLE,用于使进程进入睡眠状态,它提供了高效但可能无法杀死的TASK_UNINTERRUPTIBLE以及易于唤醒但更安全的TASK_INTERRUPTIBLE的替代方案。

这样的SO Q&A题为:什么是不间断的过程?也解释一下。

我在这本非常有趣的书中发现了这一点:《 Linux编程接口:Linux和UNIX系统编程手册》


这并不意味着您不能产生不可杀灭的过程。这仅表示,随着这些调用切换到使用新TASK_KILLABLE状态,无法终止的系统调用数量正在减少。
马丁·彼得斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.