Mensimulasikan proses yang tidak dapat diselesaikan dalam kondisi D.

14

Untuk skenario pengujian bencana pada lingkungan server luar, kami sedang mencari cara mudah untuk membuat proses macet dalam keadaan D (tidur tidak terputus).

Ada cara mudah? Contoh kode sampel C akan menjadi nilai tambah :)

Sunting - jawaban pertama adalah semi-benar, karena prosesnya ditunjukkan dalam keadaan D, tetapi masih menerima sinyal dan dapat dibunuh

er453r
sumber
Di sistem operasi yang mana? Atau apakah Anda mencari solusi portabel (tidak yakin jika ada)?
derobert
@mr_tron - ini bukan "tidak terputus" :)
er453r
1
@derobert - maaf karena tidak tepat - server ubuntu 12.04.4
er453r
1
Bagi mereka yang mencari solusi "bekerja", buka stackoverflow.com/a/22754979/2182622
noname

Jawaban:

2

Saya memiliki masalah yang sama dan menyelesaikannya dengan membuat modul kernel yang macet dalam keadaan D.

Karena saya tidak memiliki pengalaman dalam modul, saya mengambil kode dari turorial ini dengan beberapa modifikasi yang ditemukan di tempat lain .

Hasilnya adalah perangkat di / dev / memory yang macet saat dibaca tetapi bisa terbangun dengan menulisnya (perlu dua tulisan, saya tidak tahu kenapa tapi saya tidak peduli).

Untuk menggunakannya:

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

Untuk membuka blokir, dari terminal lain:

# 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

Kode untuk 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;
}
Figo
sumber
10

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

Suatu proses dimasukkan ke dalam tidur yang tidak terputus (STAT D) ketika perlu menunggu sesuatu (biasanya I / O) dan tidak boleh menangani sinyal saat menunggu. Ini berarti Anda tidak bisa kill, karena semua kill tidak mengirimkan sinyal. Ini mungkin terjadi di dunia nyata jika Anda mencabut server NFS Anda sementara mesin lain memiliki koneksi jaringan terbuka untuk itu.

Kami dapat membuat proses kami sendiri yang tidak terputus dengan durasi terbatas dengan memanfaatkan vforkpanggilan sistem. vforkseperti fork, kecuali ruang alamat tidak disalin dari orang tua ke anak, untuk mengantisipasi execyang hanya akan membuang data yang disalin. Mudah bagi kami, ketika Anda vforkorang tua menunggu tanpa gangguan (dengan cara wait_on_completion) pada anak execatau 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

Kita melihat anak ( PID 1973, PPID 1972) dalam tidur interruptible dan orang tua ( PID 1972, PPID 13291- shell) dalam tidur tidak terganggu sementara itu menunggu selama 60 detik pada anak.

Satu hal yang rapi (nakal?) Tentang skrip ini adalah bahwa proses dalam tidur yang tidak terputus berkontribusi pada rata-rata beban mesin. Jadi, Anda dapat menjalankan skrip ini 100 kali untuk sementara waktu memberi mesin rata-rata beban meningkat sebesar 100, seperti yang dilaporkan oleh uptime.

mikeserv
sumber
Persis apa yang dicari! Terima kasih banyak!
er453r
3
yang menyedihkan adalah prosesnya dalam keadaan D, tapi saya bisa membunuhnya dengan kill: /
er453r
@ er453r - maaf, teman. Saya tidak tahu banyak tentang hal itu dengan jujur ​​- jawabannya hanya salinan / tempel itulah sebabnya saya menjadikannya sebagai konten wiki komunitas . Saya membaca pertanyaan Anda, ingin tahu sendiri, lalu melakukan googling dan menemukan apa yang saya pikir merupakan informasi yang cukup menarik. Itu yang Anda lihat di atas. Tetapi suara dan sisanya tidak berkontribusi untuk reputasi saya sendiri karena itu wikied, dan karena saya agak mencurinya. Mungkin ada lebih banyak info di halaman itu yang bisa menjelaskan mengapa?
mikeserv
Terima kasih - saya sudah membacanya seperti yang Anda posting. Saya sudah mencari di internet untuk ini, tetapi setiap orang mencoba untuk menyingkirkan proses ini, bukan membuatnya: P Secara umum, pertukaran stack selalu menjadi pilihan terakhir saya :)
er453r
Ya, saya masih bisa membunuh ini juga: - /
Leo Ufimtsev
2

Pada dasarnya kamu tidak bisa. Baca artikel ini, berjudul: TASK_KILLABLE: Keadaan proses baru di Linux .

kutipan

Kernel Linux® 2.6.25 memperkenalkan status proses baru untuk mengaktifkan proses yang disebut TASK_KILLABLE, yang menawarkan alternatif untuk TASK_UNINTERRUPTIBLE yang efisien namun berpotensi tidak dapat diraih dan TASK_INTERRUIBIBLE yang mudah dibangunkan tetapi lebih aman.

T&J SO ini berjudul: Apa itu proses yang tidak terputus? juga menjelaskannya.

Saya menemukan ini dalam buku yang sangat menarik berjudul: The Linux Programming Interface: A Linux dan UNIX System Programming Handbook .

Florent
sumber
Itu tidak berarti Anda tidak dapat menghasilkan proses yang tidak dapat diraih. Ini hanya berarti bahwa jumlah panggilan sistem yang tidak dapat digunakan menurun karena panggilan-panggilan tersebut beralih ke penggunaan TASK_KILLABLEnegara baru .
Martijn Pieters