Running a new process
- Executing a new program : binary program을 읽어서 자신을 호출한 process의 메모리 영역에 덮어 씀(기존 program은 중지)
- Creating a new process(forking) : 자신을 호출한 process(parent process)를 복사하여, 새로운 process 생성
#include <unistd.h>
int excl(const char* path, const char* arg, ... /* (char*) NULL */);
int exclp(const char* file, const char* arg, ... /* (char*) NULL */);
int exele(const char* path, const char* arg, ... /* (char*) NULL, char* const envp[] */);
int execv(const char* path, char* const argv[]);
int execvp(const char* file, char* const argv[]);
int execvpe(const char* file, char* const argv[], char* const envp[]);
- Exec family of call
- path/file : 실행할 program binary
- arg/argv[] : 실행할 program의 인자(마지막에는 NULL을 넣어주어야 함)
- envp[] : program 실행 시, 새로 지정할 환경 변수(마지막에는 NULL을 넣어주어야 함)
- return : 없으면 성공, -1 : error
Example
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
printf("--> Before exec function\n");
if (execlp("ls", "ls", "-a", (char*) NULL) == -1) {
perror("execlp");
exit(1);
}
printf("--> After exec function\n"); // execlp가 실행되는 순간 process가 덮여쓰여져 이 구문은 실행되지 않음
return 0;
}
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
char* argv[3];
printf("Before exec function\n");
argv[0] = "ls";
argv[1] = "-a";
argv[2] = NULL;
if (execv("/bin/ls", argv) == -1) {
perror("execv");
exit(1);
}
printf("After exec function\n");
return 0;
}
creating a child process
#include <unistd.h>
pid_t fork(void);
- fork() system call
- 자신을 복사해 새로운 process 생성
- 부모와 자식 프로세스의 수행은 동시 진행
- 독립적으로 실행
- 같은 program binary 수행
- return
- child process's pid : parent process
- -1 : error
- 0 : child process
Example
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
pid_t pid;
switch (pid = fork()) {
case -1:
perror("fork");
exit(1);
break;
case 0:
printf("Child process - My PID:%d, My Parent's PID:%d\n",
(int)getpid(), (int)getppid());
break;
default:
printf("Parent process - My PID:%d, My Parent's PID:%d, "
"My Child's PID:%d\n", (int)getpid(), (int)getppid(), (int)pid);
break;
}
printf("End of fork\n");
return 0;
}
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
pid_t pid;
switch (pid = fork()) {
case -1:
perror("fork");
exit(1);
break;
case 0:
printf("--> Child Process\n");
if (execlp("ls", "ls", "-a", (char*)NULL) == -1) {
perror("execlp");
exit(1);
}
exit(0);
break;
default:
printf("--> Parent process - My PID:%d\n", (int)getpid());
break;
}
printf("End");
return 0;
}
Terminating a process
#include <stdlib.h>
void exit(int status);
- process가 종료되면, 어떻게 종료되었는지를 exit status에 저장
- 일반적으로 0은 정상 종료를 나타냄
- child process의 종료 상태를 parent process로 전달 가능
- exit() system call
- 기본적인 process 종료 과정 수행
- status & 0377이 부모에게 전달됨
- 종료 과정
- atexit(3)에 등록된 함수들을 등록 역순으로 수행
- Standard IO stream의 모든 내용을 모두 flush
- 모든 temporal file들 삭제
- _exit(2) 호출 : 이후 종료 과정은 kernel이 수행
- 사용 중이던 file descriptor 닫기
- 부모 프로세스에 exit status 전달
- 부모 프로세스에게 SIGCHLD signal 전달
- 자식 프로세스에게 SIGHUP signal 전달
- Process가 사용하던 자원들 반납
registering functions for exit
#include <stdlib.h>
int atexit(void (*function)(void));
- process 종료 시 호출할 함수들을 등록
- void (*function)(void) : 등록할 function prointer(return과 인자가 없은 함수)
- return
- 0 : success
- non-zero : error
Example
#include <stdlib.h>
#include <stdio.h>
void cleanup1(void) {
printf("Cleanup 1 is called.\n");
}
void cleanup2(void) {
printf("Cleanup 2 is called.\n");
}
int main(void) {
atexit(cleanup1);
atexit(cleanup2);
exit(0);
}
Process synchronization
- 다중 프로그래밍 시스템
- 여러 개의 프로세스들이 존재
- 프로세스들은 서로 독립적으로 동작
- 공유 자원 또는 데이터가 있을 때, 문제 발생 가능
- 동기화
- 프로세스들이 서로 동작을 맞추는 것
- 프로세스들이 서로 정보를 공유하는 것
Zombie process / state
- 종료되었지만, 아직 삭제되지 않은 프로세스
- 부모 프로세스보다 먼저 종료된 경우, zombie state가 됨
- 자원 등은 모두 반납
- 하지만, kernel에 최소한의 정보가 남아 있음(ex. exit status)
- 부모 프로세스가 exit status를 얻어갈 때까지 zombie process로 남아있음
acquiring exit status of a child
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int* status);
- 자식 process가 종료할 때까지 대기
- 자식 process가 종료하면 exit status를 얻어 옴(여러 개인 경우, 가장 빨리 종료된 것의 exit status를 얻어 옴)
- return
- -1 : 실행 중인 자식이 없음
- child process id : success
- status : exit status를 저장할 위치
- status 값 읽기
- exit으로 전달한 값(8bits, 비정상 종료 시 = 0), process를 종료시킨 signal(정상 종료 시 = 0)
- system마다 다를 수 있음
- Macro function 사용 추천
- WIFEXITED(status) : 정상 종료 시, true
- WEXITSTATUS(status) : 정상 종료 시 반환 값(exit()의 값)
- WIFSIGNALED(status) : 시그널에 의해 종료 시, true
Example
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int status;
pid_t pid;
switch (pid = fork()) {
case -1:
perror("fork");
exit(1);
break;
case 0:
printf("--> Child Process\n");
exit(2);
break;
default:
while (wait(&status) != pid)
continue;
printf("--> Parent Process\n");
printf("Status : %d, %x\n", status, status);
printf("Child process Exit Status:%d\n", WEXITSTATUS(status));
break;
}
return 0;
}
wait for a specific child
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int* status, int options);
- option
- WNOHANG : 자식이 종료하기 전이라도, 상태 값 바로 반환(대기하지 않고 수행을 계속 함)
- WNOWAIT : 상태 값을 반환한 child process를 대기 상태로 유지(다시 exit status를 요청할 수 있음)
Example
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int status;
pid_t pid;
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) {
printf("--> Child process\n");
sleep(3);
exit(3);
}
printf("--> Parent process\n");
while (waitpid(pid, &status, WNOHANG) == 0) {
printf("Parent still wait...\n");
sleep(1);
}
printf("Child Exit Status : %d\n", WEXITSTATUS(status));
return 0;
}
'💻 Computer Science > System' 카테고리의 다른 글
[System] 메모리 맵핑 (1) | 2024.01.26 |
---|---|
[System] 시그널 (1) | 2024.01.25 |
[System] 프로세스 (0) | 2024.01.25 |
[System] 시스템 정보 (0) | 2024.01.24 |
[System] Files in Unix/Linux (1) | 2024.01.24 |