D 상태에서 종료할 수 없는 프로세스 시뮬레이션

D 상태에서 종료할 수 없는 프로세스 시뮬레이션

서버 환경의 재해 테스트 시나리오를 위해 프로세스를 D(논스톱 절전) 상태로 전환하는 간단한 방법을 찾고 있습니다.

쉬운 방법이 있나요? C 샘플코드도 있으면 좋을 것 같아요 :)

편집하다- 프로세스가 D 상태에 있는 것으로 표시되지만 여전히 신호를 수신하고 종료될 수 있으므로 첫 번째 대답은 반정확합니다.

답변1

~에서https://blogs.oracle.com/ksplice/entry/disown_zombie_children_and_the

프로세스는방해받지 않는 수면 (STAT D)무언가를 기다려야 할 때(보통 I/O)그리고 기다리는 동안 신호를 처리해서는 안 됩니다. 이는 killKill이 수행하는 작업이 신호를 보내는 것뿐이므로 그렇게 할 수 없음을 의미합니다 . 실제로는 다른 컴퓨터가 네트워크에 연결되어 있는 동안 NFS 서버를 분리하면 이런 일이 발생할 수 있습니다.

우리는 시스템 호출을 활용하여 vfork제한된 기간 동안 중단되지 않는 자체 프로세스를 만들 수 있습니다. 복사된 데이터가 던져질 것으로 예상되므로 주소 공간이 상위에서 하위로 복사되지 않는다는 점을 제외하면 vfork유사합니다 . 부모님이 기다리는 동안 우리에게 편리함forkexecvfork논스톱(을 통해 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--shell )는 하위 프로세스를 60초 동안 기다리는 동안 중단할 수 없는 절전 상태에 있는 것을 볼 수 있습니다.

이 스크립트에 대한 한 가지 깔끔한(장난?) 점은 중단되지 않은 절전 상태에 있는 프로세스가 시스템의 로드 평균에 영향을 미친다는 것입니다. 따라서 이 스크립트를 100번 실행하여 컴퓨터의 로드 평균을 일시적으로 100만큼 늘릴 수 있습니다 uptime.

답변2

나는 같은 문제가 있었고 D 상태에 걸린 커널 모듈을 만들어 해결했습니다.

저는 모듈 경험이 없어서 처음부터이 전설몇 가지 수정 사항을 찾았습니다.엘 어딘가에.

결과적으로 /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;
}

답변3

기본적으로는 할 수 없습니다. 다음 제목의 기사를 읽어보세요.TASK_KILLABLE: Linux의 새로운 프로세스 상태.

발췌

Linux® 커널 2.6.25에는 프로세스를 절전 모드로 전환하기 위한 TASK_KILLABLE이라는 새로운 프로세스 상태가 도입되었습니다. 이는 효율적이지만 잠재적으로 종료할 수 없는 TASK_UNINTERRUPTIBLE 및 깨우기는 쉽지만 더 안전한 TASK_INTERRUPTIBLE에 대한 대안을 제공합니다.

이 SO Q&A의 제목은 다음과 같습니다.무중단 프로세스란 무엇입니까?또한 설명합니다.

나는 다음과 같은 매우 흥미로운 책에서 이것을 발견했습니다.Linux 프로그래밍 인터페이스: Linux 및 UNIX 시스템 프로그래밍 매뉴얼.

관련 정보