🔊 Program layout
- int main(int argc, char *argv[])
- argc : 인자 개수
- argv[] : 인자의 포인터를 담은 배열
- exec가 호출되면 kernel에서 program이 실행된다.
- main에서 반환되는 값을 exit(main(..));을 받아 종료된다.
- command-line argument, enviroment와 sets
🔊 main Function
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
for (i = 0; i < argc; i++)
printf("argv[%d]: %s\n", i, argv[i]);
exit(0);
}

- Environment List
- character pointer를 담은 배열의 리스트
- extern char **environ;
- 변수에 접근하기 위해서 getenv 또는 putenv를 호출해야한다.
memory layout
- TEXT(code)
- 초기화된 data segment
- 초기화되지 않은 data segment(bss)
- Stack : 지역변수
- Heap : 동적할당 메모리

- bbs는 disk에 저장되지 않는다.
- program은 text segment와 초기화된 data만 저장한다.
🔊 Process
- 실행된 program으로 process와 program은 다르다.
- 코드와 변수와 register, stack으로 이루어져있다.
- Process는 pid를 갖는다.
- process를 생성하고 관리할 수 있다. : fork, exec, wait, exit, ...
🔈 getpid( ) & getppid( )
- 모든 process는 고유한 process ID를 갖게되는데 한 프로세스 내에서 고유한 값을 가지며 이미 이용한 ID는 재사용되기도 한다.
#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void);
🔈 fork( )
- child는 parent의 data space, heap, stack를 공유하지 않고 복사하여 사용하며 text 부분은 공유한다.
#include <unistd.h>
pid_t fork(void);
pid_t pid;
pid = fork();
🔈exec( )
- 새 프로그램을 초기화할 때 이용된다.
- exec사용시에 program 생성이 되는 것이 아니기 때문에 process ID는 변하지않는다.

#include <unistd.h>
int execl(const char *pathname, const char *arg0,… );
int execv(const char *pathname, char *const argv[]);
int execle(const char *pathname, const char *arg0,…,char *const envp[]);
int execve(const char *pathname, char *const argv[], char *const envp[]);
int execlp(const char *filename, const char *arg0,... );
int execvp(const char *filename, char *const argv[]);
- p : file 이름이 인자, 나머지는 pathname
- e : environ 인자 이용
- l : 인자를 하나하나 적고 NULL로 끝낸다.
- v : 배열을 이용한다.
- ls 수행을 위해선 execl 이 수행된다.
#include <unistd.h>
main(){
printf("executing ls\n");
execl("/bin/ls", "ls", "-l", (char *)0);
perror("execl failed to run ls");
exit(1);
}
- 첫번째 인자 실행, argv[0] - ls(앞 인자와 같아서 무시), argv[1] - optional, NULL
- ls 수행을 위해선 execv 이 수행된다.
#include <unistd.h>
main()
{
char *const av[]={"ls", "-l", (char *)0};
execv("/bin/ls", av);
perror("execv failed");
exit(1);
}
🔊 exec와 fork 사용
#include <unistd.h>
int fatal(char *s){
perror(s);
exit(1);
}
main(){
pid_t pid;
switch (pid = fork()){
case -1:
fatal("fork failed");
case 0:
execl("/bin/ls", "ls", "-l", (char*)0);
fatal("exec failed");
break;
default:
wait((int*)0);
printf("ls completed\n");
exit(0);
}
}

- shell command를 실행한다.
int docommand(char *command)
{
pit_t pid;
if((pid = fork()) < 0 )
return (-1);
if(pid==0)
{
execl("/bin/sh", "sh", "-c", command, (char *)0);
perror("execl");
exit(1);
}
wait((int *)0);
return(0);
}
🔊 데이터와 file descriptor 상속
- parent가 접근 가능한 file은 child 또한 접근이 가능하다.
- child가 write하면 parent의 offset은 변경된다.

main(){
int fd;
pid_t pid;
char buf[10];
if((fd = open("data", O_RDONLY)) == -1)
fatal("open failed");
read(fd, buf, 10);
printpos("Before fork", fd);
switch(pid = fork()) {
case -1:
fatal("fork failed");
break;
case 0:
printpos("Child before read", fd);
read(fd, buf, 10);
printpos("Child after read", fd);
break;
default:
wait((int *)0);
printpos("Parent after wait", fd);
}
}
🏷️ parent와 child의 차이
- fork()의 반환값
- process ID
- time관련 정보
- file locks set
🔈 exec 와 open files
- fork이후 exec 호출시 부모와 같은 fd를 써서 문제가 발생할 수 있음
- close-on-exec flag : parent의 fd가 자동으로 close하게한다.
#inlucde <fcntl.h>
.
.
int fd;
fd = open(“file”, O_RDONLY);
.
.
fcntl(fd, F_SETFD, 1);
fcntl(fd, F_SETFD, 0);
res = fcntl(fd, F_GETFD, 0);
🖇️ example
int main(int argc, char** argv)
{
int fd;
pid_t pid;
fd = open(“test”, O_RDONLY);
pid = fork();
if(pid == 0){
execl(“exec",“child",0);
}
if(pid<0){
perror("MAIN PROCESS");
}
wait(NULL);
printf("MAIN PROCESS EXIT\n");
close(fd);
return 0;
}
int main(int argc, char** argv)
{
if( read(3, buff, 512) < 0){
perror("EXEC PROCESS");
exit(1);
}
printf("EXEC PROCESS EXIT\n”);
return 0;
}