Today
프로세스들은 process hierarchy로 되어 있다. init에서 시작해서 트리구조로 되어 있다.
쉘이라는 것은 user program인데 다른 사용자들 대신에 그 프로그램을 실행시키어 주는 프로그램이다. shell은 기본적으로 command에서 읽어서 execution해주는 역활을 한다.
int main()
{
char cmdline[MAXLINE]; /* command line */
while (1) {
/* read */
printf("> ");
Fgets(cmdline, MAXLINE, stdin);
if (feof(stdin))
exit(0);
/* evaluate */
eval(cmdline);
}
}
Execution is a sequence of read/evaluate steps 들로 이루어져 있다.
parse한다음에 command라인에서 Fork를 띄어서 ls command를 받아서 execve 시스템 콜을 받아서 실행시키고 child process를 실행시킨다.
리눅스 상에서 &
을 명령어 뒤에서 입력하면 백그라운드상에서 프로세스가 돌아가게 된다.
이제 여기에서 보다 복잡하게 하기 위해 파이프나 &
연산을 하게 된다.
parent, child모두 돌고 있는 상황인것이다. parent는 그다음 커멘드를 기다리고 있고 child는 언제끝날지 모르는 상황이다. 나중에 child가 돌다가 끝나면 child가 parent한테 나 끝났으니 reapping해달라는 매커니즘이 필요하다. 매커니즘(=signal)을 구현해야 한다.
ls -al | tail -5 라는 명령어를 입력하면 두개의 process를 띄운다음에 ls -al의 결과를 가지고 tail에 넣어서 5개만 띄운다.
shell이 2개의 process를 fork 해서 띄우고 서로 커뮤니케이션하게 된다.
각자 address space를 가지고 있고 공유 space가 없다. 서로 통신할 방법이 없다. 그래서 inter-process communication한다.
파이프는 단방향 통신 서비스이다.
#include <stdio.h>
#include <unistd.h>
int main(void) {
inr n, fd[2], pid; char line[100];
if (pipe(fd) < 0) exit(-1);
if ((pid = fork()) < 0) exit(-1);
else if (pid > 0) { /*parent */
close(fd[0]);
write(fd[1], “Hello World\n”, 12);
wait(NULL);
}
else { /* child */
close(fd[1]);
n = read(fd[0], line, MAXLINE);
write(STDOUT_FILENO, line, n);
}
}