c에서 비지역성 점프라고 부른 사용자 수준의 예외적 제어 흐름의 형태를 제공하며, 이것은 보통의 콜-리턴 순서를 통할 필요 없이 하나의 함수에서 현재 실행하고 있는 다른 함수로 제어를 이동한다. 비지역성 점프는 setjmp와 longjmp함수로 제공한다. setjmp함수는 현재 호출하는 환경을 jmp_buf 타입의 버퍼에 저장해서 후에 longjmp가 사용되며 0을 리턴한다 호출하는 환경은 프로그램 카운터, 스택 포인터, 범용 레지스터를 포함한다. 책에서는 이런 식으로 설명해 주는데, 찾아보니 goto함수는 함수의 범위를 넘어서 이동할 수 없는 제약이 있다고 한다. jmp_buf는 아키텍처별 정보를 담는데 x86의 경우에는 레지스터 정보를 담기 위해 6 개의 정수로 이뤄진다.
setjmp() 최초 호출시 0을 반환하지만 longjmp()를 통해 반환되는 경우에는 longjmp()의 두 번째 인자로 주어진 값을 반환한다. 코드 예시를 보자
#include "csapp.h"
jmp_buf buf;
int error1 = 0;
int error2 = 1;
void foo(void), bar(void);
int main()
{
switch (setjmp(buf))
{
case 0:
foo();
break;
case 1:
printf("Detected an error1 condition in foo \n");
break;
case 2:
printf("Detected an error2 condition in foo \n");
break;
default:
break;
}
exit(0);
}
void foo(void)
{
if (error1)
longjmp(buf, 1);
bar();
}
void bar(void)
{
if (error2)
longjmp(buf, 2);
}
중간에 longjmp를 둬서 에러가 발생하면 바로 longjmp가 setjmp를 호출해서 즉시 리턴된다.
비지역성 점프의 다른 증용은 시그널의 도착으로 중단되었던 인스트럭션으로 돌아가는 대신 특정 코드 위치로 시그널 핸들러를 벗어나서 분기하는 경우다.
#include "csapp.h"
sigjmp_buf buf;
vodi handler(int sig){
siglongjmp(buf,1);
}
int main(){
if (!sigsetjmp(buf,1)){
Signal(SIGINT, handler);
Sio_puts("starting \n");
}
else
Sio_puts("restarting\n");
while(1){
Sleep(1);
Sio_puts("processing .... \n");
}
exit(0);
}
코드 출처: CS:APP
'CS' 카테고리의 다른 글
프로시저 (0) | 2021.10.02 |
---|---|
전통적 동기화 문제와 데드락 (0) | 2021.09.26 |
동시성 이슈 (0) | 2021.09.25 |
Volatile 지정자 (0) | 2021.09.24 |
dup, dup2 , 파일 서술자 복제 함수 (0) | 2021.09.17 |