TASK_INTERRUPTIBLE 상태의 프로세스는 신호 전달을 통해서만 깨어날 수 있습니까?

TASK_INTERRUPTIBLE 상태의 프로세스는 신호 전달을 통해서만 깨어날 수 있습니까?

리눅스 프로그래밍 인터페이스설명하다

22.3 인터럽트 가능 및 무정전 프로세스 슬립 상태

SIGKILL 및 SIGSTOP은 항상 프로세스에 대해 즉시 조치를 취한다는 단서를 이전 명령문에 추가해야 합니다. 서로 다른 시점에 커널은 프로세스를 절전 모드로 전환할 수 있으며 다음과 같은 두 가지 절전 상태가 있습니다.

  • 작업_인터럽트 가능: 프로세스가 이벤트를 기다리고 있습니다.. 예를 들어 터미널 입력을 기다리는 중, 현재 빈 파이프에 데이터를 쓰는 중, System V 세마포어 값을 증가시키는 중입니다. 프로세스는 이 상태에서 얼마든지 시간을 보낼 수 있습니다.이 상태의 프로세스에 대해 신호가 발생하면 작업이 중단되고 신호 전달로 프로세스가 깨어납니다.ps(1)을 통해 나열되면 TASK_INTERRUPTIBLE 상태의 프로세스는 STAT(프로세스 상태) 필드에 문자 S로 표시됩니다.

  • TASK_UNINTERRUPTIBLE: 프로세스가 디스크 I/O 완료와 같은 특별한 범주의 이벤트를 기다리고 있습니다. 이 상태의 프로세스에 대해 신호가 생성되면 프로세스가 이 상태를 종료할 때까지 신호가 전달되지 않습니다. TASK_UNINTERRUPTIBLE 상태의 프로세스는 ps(1)에 의해 STAT 필드에 D가 포함되어 나열됩니다.

따라서 TASK_INTERRUPTIBLE 상태의 프로세스는 이벤트를 기다리고 있으며 해당 프로세스에 대해 생성된 신호의 전달로 깨어난다는 의미입니다.

  • 프로세스가 기다리는 이벤트와 프로세스를 깨우는 신호 사이에는 어떤 관계가 있나요? 신호는 이벤트 발생을 나타내야 합니까? 아니면 신호가 이벤트와 독립적일 수 있습니까?

  • TASK_INTERRUPTIBLE 상태의 프로세스는 신호 전달을 통해서만 깨어날 수 있습니까?

예를 들어, 프로세스가 하위 프로세스를 호출 wait()하거나 waitpid()종료를 기다리는 경우,

  • 상태가 TASK_INTERRUPTIBLE로 변경되었나요?
  • 전화가 wait()/waitpid()다시 돌아오도록 하려면 어떻게 해야 합니까? SIGCHLD의 통과일까요? 하위 프로세스가 종료되면 항상 SIGCHLD가 생성되어 프로세스에 전달됩니까?

감사해요.

답변1

프로세스가 기다리는 이벤트와 프로세스를 깨우는 신호 사이에는 어떤 관계가 있나요? 신호는 이벤트 발생을 나타내야 합니까? 아니면 신호가 이벤트와 독립적일 수 있습니까?

신호와 프로세스가 기다리고 있는 이벤트 사이에는 어떤 관계도 있을 필요가 없습니다. 귀하의 예를 사용하면 프로세스는 중단 가능한 절전 상태에 있을 수 있으며 하위 프로세스가 종료되기를 기다리고 신호에 대한 응답으로 깨어날 수 있습니다.

다음 예제 프로그램을 고려하십시오.

#include <stdio.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

static void signal_handler(int signo)
{
#define msg "received signal\n"
    write(STDOUT_FILENO, msg, sizeof(msg));
#undef msg
}

int main(void)
{
    const struct sigaction act = {
        .sa_handler = signal_handler,
        // Not including SA_RESTART in sa_flags
    };

    if (sigaction(SIGHUP, &act, NULL) < 0) {
        perror("sigaction");
        return 1;
    }

    const int pid = fork();
    if (pid < 0) {
        perror("fork");
        return 1;
    }

    if (pid == 0) {
        // Child -- hang out a while
        sleep(60);
    } else {
        // parent
        if (syscall(SYS_wait4, pid,  NULL, 0, NULL) < 0) {
            perror("wait");
        }
    }

    return 0;
}

프로그램은 먼저 SIGHUP신호에 응답하기 위해 신호 처리기를 설정합니다. 그래요아니요SA_RESTART특정 라이브러리 기능이 중단된 시스템 호출을 자동으로 다시 시작하도록 하는 이 플래그를 포함합니다 .

그런 다음 프로그램은 fork()새로운 프로세스를 생성하는 데 사용됩니다. 자식은 잠시 잠을 자고 부모는 자식이 완료될 때까지 기다립니다.

syscall(SYS_wait4,...여기서는 왜 대신 사용합니까 waitpid()? C 라이브러리 함수에 구현된 모든 동작을 제거하고 싶습니다 waitpid(). C 라이브러리 함수를 건너뛰고 바로 커널로 이동합니다.

이제 다음 프로그램을 실행할 수 있습니다.

$ ./a.out

그런 다음 다른 터미널에서 다음을 볼 수 있습니다.

$ ps aux | grep a.out
username     7839  0.0  0.0   2128   692 pts/0    S+   22:28   0:00 ./a.out
username     7840  0.0  0.0   2128    76 pts/0    S+   22:28   0:00 ./a.out

이는 S중단 가능한 절전 모드를 의미하므로 통화에서 차단된 프로세스는 wait()중단 가능한 절전 모드에 있습니다. (통화 중에 차단된 프로세스 sleep()도 Interruptible Sleep 상태에 있다는 점에 유의하세요.)

이제 프로세스에 신호를 보내면 다음과 같습니다 SIGHUP.

$ kill -HUP 7839

프로그램의 출력이 표시됩니다.

received signal
wait: Interrupted system call

received signal함수 signal_handler()호출에서 쌍 호출에 대한 응답으로 오류 (true ) Interrupted system call가 반환되었습니다. 신호 전달은 절전 모드를 중단하고 신호 처리기를 실행한 다음 호출이 반환될 때까지 기다리게 합니다 (중단된 시스템 호출).perror()waitpid()wait4()HUPEINTR

TASK_INTERRUPTIBLE 상태의 프로세스는 신호 전달을 통해서만 깨어날 수 있습니까?

신호 전달은 일방향이지만 유일한 방법은 아닙니다.오직TASK_INTERRUPTIBLE이 상태의 프로세스를 깨울 수 있는 방법입니다. 예를 들어, 입력을 기다리는 프로세스를 차단하는 경우를 생각해 보세요. 입력이 가능해지면 프로세스가 활성화됩니다. 이 경우 깨우기 프로세스에는 신호가 포함되지 않습니다.

[통화 시 프로세스 차단됨 wait()] 상태가 TASK_INTERRUPTIBLE로 변경되었나요?

예, 위를 참조하세요.

wait()/waitpid() 호출이 반환되는 원인은 무엇입니까? 그냥 SIGCHLD를 보내는 건가요? 하위 프로세스가 종료되면 항상 SIGCHLD가 생성되어 프로세스에 전달됩니까?

여기서는 (1) 커널 시스템 호출 인터페이스의 동작과 (2) C 라이브러리 함수의 동작이라는 두 가지 일이 발생합니다. 일반적으로 프로그램은 C 라이브러리 함수를 호출하고 C 라이브러리 함수는 시스템 호출을 호출합니다. 라이브러리 함수는 시스템 호출의 반환 값을 확인할 수 있습니다. 예를 들어, 이전 호출이 반환되었지만 EINTR알 수 없는 경우 시스템 호출을 다시 호출할 수 있습니다 .

관련 정보