NAME

sigreturn, rt_sigreturn - 시그널 핸들러에서 반환하고 스택 프레임 정리하기

SYNOPSIS

int sigreturn(...);

DESCRIPTION

어느 프로세스에게 블록 안 된 시그널이 대기 중이라고 리눅스 커널이 판단하면 그 프로세스 사용자 모드로 다음 번 전환할 때 (가령 시스템 호출에서 반환할 때나 그 프로세스를 CPU로 다시 스케줄 할 때) 사용자 공간 스택에 새 프레임을 만들어서 다양한 프로세스 문맥 조각들(프로세서 상태 워드, 레지스터들, 시그널 마스크, 시그널 스택 설정)을 저장한다.

또한 커널은 사용자 모드로의 전환 중에 시그널 핸들러가 호출되도록 하고, 핸들러가 반환하면 흔히 "시그널 트램펄린(signal trampoline)"이라고 하는 사용자 공간 코드 조각으로 제어가 넘어가게 한다. 그러면 시그널 트램펄린 코드에서 sigreturn()을 호출한다.

sigreturn() 호출은 앞서 시그널 핸들러를 호출하기 위해 했던 것들(프로세스 시그널 마스크 바꾸기, 시그널 스택(sigaltstack(2) 참고) 전환하기)을 모두 되돌린다. 앞서 사용자 공간 스택에 저장했던 정보를 이용해 sigreturn()은 프로세스의 시그널 마스크를 복원하고, 스택을 전환하고, 프로세스의 문맥(프로세서 플래그 및 레지스터들, 스택 포인터와 인스트럭션 포인터 포함)을 복원하여 시그널에 의해 중단됐던 지점에서 프로세스가 실행을 재개하도록 한다.

RETURN VALUE

sigreturn()은 절대 반환하지 않는다.

CONFORMING TO

많은 유닉스류 시스템에는 sigreturn() 시스템 호출이나 그에 가까운 등가물이 있다. 하지만 이 호출은 POSIX에 명세되어 있지 않으며 시스템에 따라 동작 세부 내용이 다르다.

NOTES

sigreturn()은 시그널 핸들러를 구현할 수 있도록 하기 위해서만 존재한다. 절대로 직접 호출해서는 안 된다. (실제로 GNU C 라이브러리의 간이 sigreturn() 래퍼는 -1을 반환하고 errnoENOSYS로 설정하기만 한다.) sigreturn()에 전달하는 인자들의 세부 내용은 아키텍처에 따라 다르다. (x86-64 같은 일부 아키텍처에서는 sigreturn()이 아무 인자도 받지 않는다. 앞서 커널이 사용자 공간 스택에 만들었던 스택 프레임 내에 필요한 모든 정보가 있기 때문이다.)

옛날 옛적에는 유닉스 시스템에서 시그널 트램펄린 코드를 사용자 스택에 두었다. 요즘은 사용자 스택 페이지들을 보호하여 코드 실행을 불허한다. 그래서 현대 리눅스 시스템에서는 아키텍처에 따라 시그널 트램펄린 코드가 vdso(7)나 C 라이브러리 중 한쪽에 있다. 후자의 경우에 C 라이브러리의 sigaction(2) 래퍼 함수가 sigaction 구조체의 sa_restorer 필드에 주소를 넣어서 트램펄린 코드의 위치를 알려 주며, 그때 sa_flags 필드에 SA_RESTORER 플래그를 설정한다.

저장된 프로세스 문맥 정보가 ucontext_t 구조체(<sys/ucontext.h> 참고)에 들어간다. SA_SIGINFO 플래그를 쓴 sigaction(2)을 통해 설정한 핸들러 내에서 세 번째 인자로 그 구조체를 볼 수 있다.

몇몇 다른 유닉스 시스템들에선 시그널 트램펄린의 동작이 살짝 다르다. 구체적으로 어떤 시스템에서는 사용자 모드로 전환 시 커널이 (시그널 핸들러가 아닌) 트램펄린에게 제어를 넘기며, 그 트램펄린 코드가 시그널 핸들러를 (그리고 핸들러 반환 후 sigreturn()을) 호출한다.

C 라이브러리/커널 차이

원래 리눅스 시스템 호출의 이름은 sigreturn()이었다. 하지만 리눅스 2.2에 실시간 시그널이 추가되면서 확장된 sigset_t 타입을 지원하기 위해 새로운 시스템 호출 rt_sigreturn()이 추가되었다. GNU C 라이브러리에서 이런 세부 사항을 감추고 커널이 제공할 때 투명하게 rt_sigreturn()를 이용한다.

SEE ALSO

kill(2), restart_syscall(2), sigaltstack(2), signal(2), getcontext(3), signal(7), vdso(7)


2021-03-22