D状態で殺せないプロセスをシミュレートする


14

サーバー環境での大惨事テストのシナリオでは、プロセスをD(割り込み不可能なスリープ)状態でスタックさせる簡単な方法を探しています。

簡単な方法はありますか?サンプルのCサンプルコードはプラスになります:)

編集 -プロセスがD状態にあることが示されているため、最初の答えは半正解ですが、シグナルを受信し、強制終了することができます



どのオペレーティングシステムですか?または、ポータブルソリューションを探していますか(存在するかどうかわかりません)?
デロバート14

@mr_tron-これは「割り込み不可能」ではありません:)
er453r 14年

1
@デロバート-正確ではないため申し訳ありません-Ubuntuサーバー12.04.4
er453r

1
「実用的な」ソリューションを探している人は、stackoverflow.com
noname

回答:


2

私は同じ問題を抱えており、D状態でスタックするカーネルモジュールを作成することで解決しました。

私はモジュールの経験が全くないので、どこかでesleが見つかったいくつかの修正を加えて、このturorialからコードを取り出しました

その結果、/ dev / memoryにあるデバイスが読み取りで停止しますが、書き込みを行うと起動することができます(書き込みが2回必要です。理由はわかりませんが、気にしません)。

ちょうどそれを使用するには:

# 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が親が子供のor で(を経由して)途切れることなく待機するときです。wait_on_completionexecexit

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秒間待機している間、割り込み不可能なスリープ状態にあることがわかります。

このスクリプトに関するきちんとした(いたずらな?)ことの1つは、割り込み不可能なスリープ状態のプロセスがマシンの平均負荷に寄与することです。そのため、このスクリプトを100回実行して、で報告されてuptimeいるように、一時的に100の負荷平均をマシンに与えることができます。


まさに探していたものです!どうもありがとうございました!
er453r 14年

3
悲しいことは、プロセスがD状態にあることですが、私はそれを殺すことができますkill:/
er453r 14年

@ er453r-ごめんなさい、男。私はそれについて正直なところあまり知りません-答えは単なるコピー/貼り付けでした。それが私がそれをコミュニティwikiコンテンツとして設定した理由です。私はあなたの質問を読んで、自分自身に興味を持ち、グーグルで調べて、かなり興味深い情報だと思ったものを見つけました。それはあなたが上に見るものです。しかし、投票と残りは、Wikiであり、私がそれを盗んだので、私の評判に貢献しません。そのページには、その理由を説明できる情報がもっとあるのでしょうか?
mikeserv 14年

ありがとう-投稿したとおりに読んだ。私はすでにこのため、インターネットを検索しましたが、一人一人の試みは、このプロセスを取り除くために、それらを作成しない:Pは、一般的に、スタック交換は常に:)私のための最後の手段である
er453r

うん、私はまだこれを殺すこともできます:-/
レオウフィムツェフ

2

基本的に、できません。TASK_KILLABLE:Linuxの新しいプロセス状態というタイトルのこの記事を読んでください。

抜粋

Linux®カーネル2.6.25では、TASK_KILLABLEと呼ばれるプロセスをスリープ状態にするための新しいプロセス状態が導入されました。これは、効率的だが潜在的に殺せないTASK_UNINTERRUPTIBLEおよび目覚めやすいが安全なTASK_INTERRUPTIBLEの代替を提供します。

このSO Q&Aタイトル:中断できないプロセスとは何ですか?それも説明しています。

これは、「Linuxプログラミングインターフェイス:LinuxおよびUNIXシステムプログラミングハンドブック」というタイトルの非常に興味深い本で発見しました。


だからといって、殺せないプロセスを作り出せないわけではありません。それは、それらの呼び出しが新しいTASK_KILLABLE状態を使用するように切り替わると、殺せないシステム呼び出しの数が減少していることを意味します。
マーティンピーターズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.