Моделюйте процес, який не можна отримати в стані D


14

Для сценаріїв тестування на катастрофи у зовнішньому середовищі сервера ми шукаємо простий спосіб зробити процес, застрягший у стані D (безперебійного сну).

Будь-які прості способи? Приклад C зразок коду буде плюсом :)

Редагувати - перша відповідь напівправильна, оскільки, як показано, процес знаходиться в стані D, але він все одно приймає сигнали і може бути вбитий



На якій операційній системі? Або ви шукаєте портативне рішення (не впевнений, чи є)?
дероберт

@mr_tron - це не "безперебійне" :)
er453r

1
@derobert - вибачте за неточність
er453r

1
Для тих, хто шукає "робочого" рішення, перейдіть на сторінку stackoverflow.com/a/22754979/2182622
noname

Відповіді:


2

У мене була та сама проблема, і я її вирішив, створивши модуль ядра, який застряг у стані D.

Оскільки у мене немає ніякого досвіду роботи з модулями, я взяв код із цього туроріалу з деякими модифікаціями, знайденими десь esle .

У результаті виходить пристрій в / dev / memory, який затримується при читанні, але його можна прокинути, написавши на ньому (йому потрібно дві записи, я не знаю, чому, але мені все одно).

Щоб використовувати його просто:

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

Щоб розблокувати, з іншого терміналу:

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

Makefile:

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

Процес вводиться в режим безперебійного сну, (STAT D) коли йому потрібно чекати чогось (як правило, вводу / виводу) і не повинен обробляти сигнали під час очікування. Це означає, що ви цього не можете kill, оскільки все вбиття - це надсилання сигналів. Це може статися в реальному світі, якщо ви відключите NFS-сервер, тоді як інші машини мають відкрите мережеве підключення до нього.

Ми можемо створювати власні безперебійні процеси обмеженої тривалості, скориставшись 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

3
сумно те, що процес знаходиться в стані D, але я в змозі його вбити kill: /
er453r

@ er453r - вибач, чоловіче. Я чесно не знаю про це чесно - відповідь була просто копією / вставкою, тому я встановив це як вміст вікі спільноти . Я прочитав ваше запитання, мені було цікаво, потім я трохи погукав і виявив, що мені здається, досить цікаву інформацію. Це те, що ви бачите вище. Але голоси та решта не сприяють моїй власній репутації через те, що це wiki та тому, що я начебто вкрав його. Можливо, на цій сторінці є більше інформації, яка могла б пояснити, чому?
mikeserv

Дякую - я прочитав його так само, як ви його опублікували. Я вже шукав це в Інтернеті, але кожен намагається позбутися цих процесів, а не створювати їх: P Взагалі обмін
стеками

Так, я все ще можу це вбити: - /
Лев Уфімцев

2

В основному, ви не можете. Прочитайте цю статтю під назвою: TASK_KILLABLE: новий стан процесу в Linux .

витяг

Ядро Linux® 2.6.25 запровадило новий стан процесу переходу у режим сну під назвою TASK_KILLABLE, який пропонує альтернативу ефективному, але потенційно недоступному TASK_UNINTERRUPTIBLE та легко пробуджуваному, але безпечнішому TASK_INTERRUPTIBLE.

Це запитання та відповіді під назвою: Що таке безперебійний процес? також пояснює це.

Я виявив це в цій дуже цікавій книзі під назвою: Інтерфейс програмування Linux : Посібник з програмування Linux та UNIX .


Це не означає, що ви не можете створити процес, який не можна отримати. Це просто означає, що кількість системних дзвінків, які не можна скасувати, зменшується, коли ці виклики переходять на використання нового TASK_KILLABLEстану.
Martijn Pieters
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.