for가 fork인 이유…
pid_t fork (const char *thread_name);
시스템 콜 fork는 인자로 전달한 thread_name 의 이름을 가진 복제본 프로세스를 생성한다.
이때 복제본이라는 것은 동일한 유저가상메모리
, 동일한 fd_list
(file_descriptor 리스트), 동일한 user-level 문맥
을 가져야 한다는 것을 의미한다. fork 함수는 부모프로세스에게 복제본 프로세스(이하 자식 프로세스)의 pid를 반환하며, 자식 프로세스의 경우 이 값이 0 이다.
예를 들어, a = fork(process) 를 실행하면 fork() 함수가 리턴되기 직전에는 두 개의 프로세스가 존재한다. 하나는 fork()를 실행한 부모 프로세스이고, 나머지 하나는 fork()로 인해 생성된 자식 프로세스이다. 이때 fork()가 리턴하는 값 a는 부모 프로세스의 경우에는 자식 프로세스의 pid이고, 자식 프로세스의 경우에는 0 이다. 따라서 이 값으로 부모 프로세스와 자식 프로세스를 구분할 수 있다.
부모 프로세스는 fork를 반환하기 전에 자식 프로세스가 성공적으로 복제되어있는지의 여부를 반드시 알아야 한다. 따라서 자식 프로세스가 리소스를 모두 복제할 때까지 기다려야 하며, 자식 프로세스가 리소스를 복제하지 못하면 부모의 fork() 호출은 TID_ERROR를 반환한다.
fork를 실행하면 시스템 콜 핸들러에 의해 syscall_fork가 실행된다.
pid_t syscall_fork (struct intr_frame *f){
char *thread_name = f->R.rdi;
int return_value;
return_value = process_fork(thread_name, f);
f->R.rax = return_value;
}
syscall_fork는 process_fork 라는 함수에 스레드 이름과 인터럽트 프레임을 인자로 전달해서 호출한다.
인터럽트 프레임에는 부모 프로세스가 유저모드에서 실행했던 모든 문맥들이 담겨있기 때문에 자식 프로세스는 이 정보를 자신의 스레드 구조체 내의 tf 로 갖고 있어야 한다.
tid_t process_fork(const char *name, struct intr_frame *if_)
{
struct fork_info *fork_info = (struct fork_info *)malloc(sizeof(struct fork_info));
fork_info->parent_t = thread_current();
fork_info->if_ = if_;
tid_t pid = thread_create(name, PRI_DEFAULT, __do_fork, fork_info);
process_fork_sema_down();
if (!thread_current()->child_forked_ok)
{
return -1;
}
return pid;
}
🔎 fork_sema 의 흐름에 대한 정리는 여기서!