Linux 신호는 특정 이벤트 발생 프로세스를 알리거나 프로세스가 특정 처리 기능을 실행하도록 하는 데 사용됩니다. 신호는 Unix 제품군의 고대 통신 메커니즘으로 터미널의 키보드 문자 입력에서 나올 수 있습니다. 예를 들어 control-C에 의해 트리거된 SIGINIT는 잘못된 주소에 액세스하는 애플리케이션에 의해 트리거된 SIGSEGV, 타이머 만료에 의해 트리거된 SIGALARM 등과 같은 하드웨어 또는 소프트웨어와 관련된 예외에서 발생할 수도 있습니다.
이 튜토리얼의 운영 환경: linux5.9.8 시스템, Dell G3 컴퓨터.
Linux 신호는 무엇에 사용되나요?
Linux의 신호 처리 메커니즘
Signal은 Unix 계열의 고대 통신 메커니즘으로, 특정 이벤트 발생 프로세스를 알리거나 프로세스가 특정 처리 기능을 실행하도록 하는 데 주로 사용됩니다. 1세대 유닉스 시스템에도 존재했기 때문에 고대의 것이라고 한다.
신호는 control-C에 의해 트리거되는 SIGINIT와 같이 터미널의 키보드 문자 입력에서 나올 수 있으며, 애플리케이션에 의해 트리거되는 SIGSEGV와 같은 하드웨어 또는 소프트웨어와 관련된 예외에서도 나올 수도 있습니다. 잘못된 주소에 액세스(세그먼트 오류), 타이머 만료로 인해 SIGALARM이 트리거됨 이러한 신호는 커널에 의해 프로세스로 전송됩니다.
프로세스에서 수신한 신호는 다른 프로세스에서도 올 수 있습니다. 그러나 모든 프로세스가 다른 프로세스에 신호를 보낼 수 있는 것은 아닙니다. 루트 권한이 있는 슈퍼 사용자만 이 작업을 수행할 수 있습니다. 일반 사용자 프로세스의 경우 동일한 사용자에 속한 프로세스에만 신호를 보낼 수 있습니다.
프로세스가 커널에 신호를 보낼 수 있나요? 가능하지만 커널 스레드는 응답하지 않으며 커널 코드를 수정하지 않는 한 쓸모가 없습니다.
일반적으로 신호는 비동기 메커니즘으로 간주되지만 Linux 코드에서는 예외로 인해 발생하는 다음 신호를 "동기"라고도 합니다.
#define SYNCHRONOUS_MASK \ (sigmask(SIGSEGV) | sigmask(SIGBUS) | sigmask(SIGILL) | \ sigmask(SIGTRAP) | sigmask(SIGFPE) | sigmask(SIGSYS))
여기서는 신호를 수신하는 프로세스를 "대상" 프로세스라고 부릅니다. 전통적인 신호 전송 기능은 kill()입니다. 이 이름은 무섭게 보이며 대상 프로세스가 곧 "죽일" 것 같은 느낌이 듭니다. 실제로 모든 신호는 kill()을 사용하여 전송되지만 실제로는 프로세스 중 일부만 "종료"해야 합니다. 물론 이제 더 강력한 기능과 더 친숙한 이름을 갖춘 sigqueue()가 있습니다.
두 가지의 함수 프로토타입을 살펴보겠습니다.
int kill(pid_t pid, int sig);int sigqueue(pid_t pid, int sig, const union sigval value);
pid는 대상 프로세스의 PID를 나타냅니다. Linux에서 프로세스의 PID는 모두 양수입니다. 매개변수 pid의 값이 0이거나 음수이면 불법인가요? 아니요, 사실 0과 음수는 여기서 다른 용도로 사용됩니다. Linux에는 특정 유형의 프로세스 모음을 나타내는 프로세스 그룹이라는 개념이 있습니다. kill()에서 매개변수 pid가 "0"이면 현재 프로세스가 위치한 프로세스 그룹의 모든 프로세스에 신호를 보낸다는 뜻이다. "-1"보다 작으면 신호를 보낸다. 프로세스 그룹 번호는 -pid입니다.
__kill_pgrp_info(sig, info, pid ? find_vpid(-pid) : task_pgrp(current));
pid는 "-1"입니다. 이는 Init 프로세스와 자체를 제외한 모든 프로세스 또는 자신을 제외하고 pid가 1보다 큰 모든 프로세스로 전송된다는 의미입니다.
for_each_process(p) {
if (task_pid_vnr(p) > 1 && !same_thread_group(p, current))
...
여기의 pid가 프로세스 자체 PID라면 프로세스는 자신에게 신호를 보냅니다. 이를 위해 Linux는 raise() 함수라는 더 간단한 인터페이스도 제공합니다.
kill(getpid(), sig) --> raise(sig)
sigqueue()에서는 매개변수 pid 값을 음수로 설정하여 전체 프로세스 그룹에 신호를 보낼 수 없다는 점에 유의해야 합니다.
sig는 전송될 신호의 번호를 나타냅니다. Linux의 신호 번호는 1부터 시작합니다. 매개변수 sig의 값이 0이면 어떻게 될까요? 여기서 0은 마법 같은 효과도 있습니다. sig가 "0"이면 실제로 대상 프로세스(또는 프로세스 그룹)에 신호를 보내는 것이 아니라 대상 프로세스(또는 프로세스 그룹)가 존재하는지 감지하는 데 사용됩니다.
sigqueue가 추가한 세 번째 매개변수의 정의는 다음과 같습니다.
union sigval {
int sival_int;
void __user *sival_ptr;};
传统的信号是没有传递消息的功能的,sigval算是稍微扩展了一下信号的通信能力。比如,通信双方可以事先约定某些事件为特定的int值,这个"sival_int"就可以用来保存具体的int值,目标进程可以据此来区分不同的事件,做出不同的响应。当然,这种方法传递的消息内容受限,且不易扩展,因而不适合用作常规的通信手段。
就算是进程之间发送信号,那也是要经过内核的,可以理解成是被内核“截获”了吧。
由于内核态和用户态的切换操作在不同的硬件体系架构上是不同的,而且有一些信号,比如SIGCHLD和SIGSTOP,其实现也是和架构相关的,所以Linux中signal机制的很多代码都是放在架构相关的目录下的,比如"/arch/arm/kernel/signal.c"。
一个信号的相关信息在内核中用siginfo_t结构体表示:
siginfo_t{
int si_signo;
int si_sicode;
union __sifields _sifields;
...}
内核在截获到一个进程发送的信号后,会首先做一系列的检查,比如该信号的值是否合法啦,进程有没有发送这个信号的权限啦。如果检查通过,就调用copy_from_user()将该信号的相关信息复制到siginfo_t结构体中。
相关推荐:《Linux视频教程》
위 내용은 리눅스 신호는 무엇에 사용됩니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!