본문 바로가기

CS

Nonlocal jumps

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