Simulieren Sie einen nicht tötbaren Prozess im D-Zustand


14

Für Katastrophen-Testszenarien in unserer Server-Umgebung suchen wir nach einer einfachen Möglichkeit, einen Prozess in den Zustand D (unterbrechungsfreier Ruhezustand) zu versetzen.

Irgendwelche einfachen Wege? Ein Beispiel-C-Beispielcode wäre ein Plus :)

Bearbeiten - Die erste Antwort ist halbkorrekt, da angezeigt wird, dass sich der Prozess im Status D befindet, er jedoch weiterhin Signale empfängt und abgebrochen werden kann



Auf welchem ​​Betriebssystem? Oder suchen Sie eine tragbare Lösung (nicht sicher, ob es eine gibt)?
Derobert

@ mr_tron - das ist nicht "unterbrechungsfrei" :)
er453r

1
@derobert - Entschuldigung für die Ungenauigkeit - Ubuntu Server 12.04.4
er453r

1
Für diejenigen , die für eine „arbeiten“ Lösung suchen, gehen Sie zu stackoverflow.com/a/22754979/2182622
noname

Antworten:


2

Ich hatte das gleiche Problem und löste es, indem ich ein Kernelmodul erstellte, das im D-Zustand hängen bleibt.

Da ich keine Erfahrung mit Modulen habe, habe ich den Code aus diesem Turorial mit einigen Änderungen übernommen, die irgendwo anders gefunden wurden .

Das Ergebnis ist ein Gerät auf / dev / memory, das beim Lesen hängen bleibt, aber beim Schreiben darauf aufgeweckt werden kann (es benötigt zwei Schreibvorgänge, ich weiß nicht warum, aber es ist mir egal).

Um es einfach zu benutzen:

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

So entsperren Sie von einem anderen Terminal aus:

# 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

Code für 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

Von https://blogs.oracle.com/ksplice/entry/disown_zombie_children_and_the

Ein Prozess wird in einen unterbrechungsfreien Ruhezustand versetzt, (STAT D) wenn er auf etwas warten muss (normalerweise E / A) und während des Wartens keine Signale verarbeiten soll. Das bedeutet, dass Sie es nicht killkönnen, weil alles, was Sie töten, das Senden von Signalen ist. Dies kann in der Praxis vorkommen, wenn Sie Ihren NFS-Server vom Computer trennen, während andere Computer über offene Netzwerkverbindungen verfügen.

Wir können unsere eigenen unterbrechungsfreien Prozesse von begrenzter Dauer erstellen, indem wir den vforkSystemaufruf nutzen. vforkist wie fork, mit der Ausnahme, dass der Adressraum nicht vom Elternteil in das Kind kopiert wird, in Erwartung einer, execdie nur die kopierten Daten wegwerfen würde. Günstig für uns, wenn Sie vforkals Eltern ununterbrochen (über wait_on_completion) auf das Kind warten execoder 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

Wir sehen das Kind ( PID 1973, PPID 1972) in einem ununterbrochenen Schlaf und das Elternteil (PID 1972, PPID 13291 - die Muschel) in einem ununterbrochenen Schlaf, während es 60 Sekunden auf das Kind wartet.

Eine nette (schelmische?) Sache an diesem Skript ist, dass Prozesse in einem unterbrechungsfreien Schlaf zur durchschnittlichen Auslastung einer Maschine beitragen. Sie können dieses Skript also 100-mal ausführen, um einer Maschine vorübergehend einen um 100 erhöhten Lastdurchschnitt zu geben, wie von gemeldet uptime.


Genau das, wonach gesucht wurde! Vielen Dank!
Er453r

3
Das Traurige ist, dass der Prozess im D-Zustand ist, aber ich kann ihn töten mit kill: /
er453r

@ er453r - Entschuldigung, Mann. Ich weiß ehrlich gesagt nicht viel darüber - die Antwort war nur Kopieren / Einfügen, weshalb ich sie als Community-Wiki- Inhalt festgelegt habe. Ich habe Ihre Frage gelesen, war selbst neugierig, habe dann gegoogelt und bin auf einige meiner Meinung nach recht interessante Informationen gestoßen. Das ist, was Sie oben sehen. Aber die Stimmen und der Rest tragen nicht zu meinem eigenen Ruf bei, weil es verrückt ist und ich es irgendwie gestohlen habe. Vielleicht gibt es auf dieser Seite mehr Informationen, die erklären könnten, warum?
mikeserv

Danke - ich habe es so gelesen, wie du es gepostet hast. Ich habe bereits im Internet danach gesucht, aber jeder versucht, diese Prozesse loszuwerden, nicht sie zu erstellen: P Im Allgemeinen ist der
Stapelaustausch

Ja, ich kann das auch noch töten: - /
Leo Ufimtsev

2

Im Grunde kann man nicht. Lesen Sie diesen Artikel mit dem Titel: TASK_KILLABLE: Neuer Prozessstatus unter Linux .

Auszug

Der Linux®-Kernel 2.6.25 hat einen neuen Prozessstatus eingeführt, mit dem Prozesse in den Ruhezustand versetzt werden können. Er heißt TASK_KILLABLE und bietet eine Alternative zu den effizienten, aber möglicherweise nicht zu tötenden TASK_UNINTERRUPTIBLE und den einfach zu erwachenden, aber sichereren TASK_INTERRUPTIBLE.

Diese SO Q & A mit dem Titel: Was ist ein unterbrechungsfreier Prozess? erklärt es auch.

Das habe ich in diesem sehr interessanten Buch mit dem Titel " Die Linux-Programmierschnittstelle: Ein Handbuch zur Linux- und UNIX-Systemprogrammierung" entdeckt .


Das heißt nicht, dass Sie keinen unmöglichen Prozess produzieren können. Dies bedeutet lediglich, dass die Anzahl der Systemanrufe, die nicht erledigt werden können, sinkt, wenn diese Anrufe auf den neuen TASK_KILLABLEStatus umschalten .
Martijn Pieters
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.