Researcher to DeveloperBasic 프로세스 생성 시스템 콜 - fork(), exec() - 1Probe29 2020. 12. 31. 17:52 #프로세스의 기본 구조 STACK = 함수 처리를 위한 영역 HEAP = 동적 메모리 DATA = 초기값이 있는 변수값 (int i=0;) BSS = 초기값이 없는 변수값 (int i;) TEXT = Code, 실행 코드 이미지 이 기본 구조에서 STACT, HEAP은 Code가 실행되면서 줄어들거나 커지거나 하지만 DATA, BSS, TEXT는 컴파일시 결정되는 영역이다. 아주 간단하게는 전체 메모리 공간을 만들고 프로세스 이미지(코드 이미지)를 해당 공간에 업로드하고 실행 시작(STACK, HEAP 처리)하므로써 프로세스를 생성한다고 볼 수 있다. #fork() 유닉스, 리눅스 시스템 콜 중 하나 새로운 프로세스 공간을 별도로 만들고, fork() 시스템 콜을 호출한 부모 프로세스 공간의 데이터을 모두 복사한다. =copy 기존에 실행되고 있었던 부모 프로세스에 있는 모든 내용을 자식 프로세스에 copy한다. 프로세스 안에 있는 fork() 시스템 콜을 실행하면 새로운 프로세스 공간(동일한 코드, 데이터를 가짐)을 만든 다음에 fork() 다음 줄에 Program Counter가 놓여서 동일한 Code를 읽어나가게 된다. 이 때 fork() 의 return value에서 pid가 나오는데 0 일 경우에는 자식 프로세스이고 0 보다 큰 값일 경우 부모 프로세스의 pid로 리턴이 되어서 자식, 부모 프로세스 간에 실행을 각각 따로 할 수 있다. 부모 프로세스가 있는 상태에서 #fork() 시스템 콜 헤더 파일 <unistd.h> 함수 원형 pid_t fork(void); 특이한 것은 별도의 인자가 없음 pid_t에 대한 return 값은 부모, 자식 프로세스가 다르다. 함수는 다음과 같다. #include <sys/types.h> 자식 프로세스는 pid가 0으로 return 되고 부모 프로세스는 pid가 실제 프로세스의 pid으로 return 되어 자식, 부모 프로세스를 pid를 이용해서 구분할 수 있다. 그 다음 gcc forktest.c -o forktest 로 컴파일 해주고 ./forktest 라고 입력해서 실행해주면 다음과 같은 결과창을 확인할 수 있다. Before fork() call 정리하자면 부모 프로세스는 실제 pid값으로 리턴이 된다. #exec() 유닉스, 리눅스 시스템 콜 중 하나 =덮어씌움 exec() 시스템 콜을 호출한 현재 프로세스 공간의 TEXT, DATA, BSS 영역을 새로운 프로세스의 이미지로 덮어씌운다. 별도의 프로세스 공간을 만들지 않는다. exec 계열 함수는 현재 프로세스 이미지를 별도 메모리 공간에 복사하지 않는다. #exec() 시스템 콜 (기본적으로 6가지) 1. execl() #include <unistd.h> //execl 때문에 사용한 라이브러리 * bin/ls 전체 실행파일 이름을 인자로 적어주고 2,3번째 인자는 각각 argv[0], argv[1] 에 해당하는 내용이다. 끝에는 무조건 NULL 을 쓰게되어있다. 하나의 프로세스 공간에 저장되어 있는 code에서 컴파일 해준다음 #명령어 인수 리스트 argc 는 인자갯수를 나타내고 ls -al #execl(), execlp(), execle() 시스템콜 사용법 1. execl execl("/bin/ls", "ls", "-al", NULL); ("디렉토리와 파일 이름이 합친 전체 이름", "명령어 인수 리스트", "끝은 NULL로 끝나야 함"); 파일 이름으로 해당 프로세스로 실행한 프로세스의 환경변수 중 하나인 path를 검색함 2. execlp execl("ls", "ls", "-al", NULL); ("파일 이름", "명령어 인수 리스트", "끝은 NULL로 끝나야 함");
* 다음은 인자를 일종의 변수로 미리 만들어서 넣을 때 사용하는 exec() 시스템 콜이다. char *envp[] = {"USER=dave", "PATH=/bin", (char *)0}; 환경 변수를 별도로 설정하고자 할 때 envp에 작성, 미리 환경변수를 정의해서 넘겨줘야한다. execl 와 인자는 같지만 NULL 뒤에 envp(string 변수)를 지정해주어야 한다. 4. execv() char *arg[] = {"is", "-al", NULL}; // 인수 리스트를 내용으로 하는 문자열 배열 5. execvp() char *arg[] = {"is", "-al", NULL}; //인수 리스트를 내용으로 하는 문자열 배열 파일 이름을 해당 프로세스를 실행한 프로세스의 환경변수 중 하나인 path를 검색함 6. execve() char *envp[] = {"USER=dave", "PATH=/bin", (char *)0}; // 환경 변수를 지정하고자 할 때 * execve 예제 #include <unistd.h> printf("execute ls\n")' 여기서 환경 변수에 파일 이름(path)을 넣어주지 않았기 때문에 execl is failed 라는 내용이 나올 것 execlp, execvp 는 파일명만 넘겨주면 프로세스 환경변수(path)에서 파일명(실행파일)을 검색하겠다 execl, execv 는 파일명을 전체 경로로 포함해서 넘겨줘야하고 execle. execve 는 환경변수(path 포함 가능)를 별도로 정의해서 넘겨줘야한다. v 와 l 의 차이 : argv(인자)를 설정해서 넣겠냐 아니면 직접 써주겠냐의 차이 'Basic' 카테고리의 다른 글
|