-
[SW 정글 72일차] Pintos project 2 - System Calls 마무으리기타/SW 사관학교 정글 2021. 10. 14. 02:10
/* 구현 완료 */ void halt (void) NO_RETURN; /* 구현 완료 */ void exit (int status) NO_RETURN; /* 구현 완료 */ int exec (const char *file); /* 구현 완료 */ int wait (pid_t); /* 구현 완료 */ int filesize (int fd); /* 구현 완료 */ void seek (int fd, unsigned position); /* 구현 완료 */ unsigned tell (int fd); /* 이해 미숙 */ bool create (const char *file, unsigned initial_size); /* 이해 미숙 */ bool remove (const char *file); int open (const char *file); int read (int fd, void *buffer, unsigned length); int write (int fd, const void *buffer, unsigned length); void close (int fd); pid_t fork (const char *thread_name);
1. tid_t fork(const char *thread_name, struct intr_frame *f)
fork는 현재 실행 중인 프로세스를 인자로 받은 thread_name으로 복제하여 새로운 프로세스를 만드는 syscall이다.
복제들 할 때에 calle-saved register인 %RBX, %RSP, %RBP, and %R12 - %R15의 값은 복제안해도 된다.
여기서 calle-saved register에 대해 간단히 알고 넘어가자.
우리가 코딩을 통해 프로그램을 만들면 실행 시에 main()을 찾아 시작점으로 정해진다.
main() 안에서 어떠한 함수 func()를 호출하면 main()은 caller가 되고 func()는 calle가 된다.
그러면 여기서 calle가 실행될 때 연산을 수행하기 위해서는 어떠한 값들이 register에 저장될 것이고 그 register가 calle-saved-register이다.
즉, calle-saved-register는 콜리가 저장하는 레지스터로 콜리가 사용하기 전에 반드시 백업해야 하는 레지스터이다.
콜리 입장에서는 콜러가 백업을 필요로 하는 레지스터가 무엇인지 모르기 때문에 반드시 백업을 해주어야한다.
그러면 왜 fork 시에 calle-saved-register를 clone안해도 될까?라는 의문을 가질 수 있다.
내가 생각하기에는 현재 실행 중인 스레드의 흐름에 따라 어떠한 함수(caller)가 호출한 함수(calle)에 대한 값들이 저장된 것이므로 fork된 프로세스가 이 값들을 사용할 일이 없기 때문이라고 생각한다.fork는 두 번의 리턴을 하는 syscall인데 하나는 child process(fork를 통해 생성된 프로세스)입장에서는 0을 리턴받고 parent process(fork를 호출한 프로세스)는 fork를 실패했을 경우에는 TID_ERROR를 반환받고 성공했을 때 child process의 PID를 리턴받는다.
구현은 다음과 같다.
일단은 process.c파일에 tid_t process_fork(const char *name, struct intr_frame *if_)함수가 있으므로 이것을 reimplement시켰다.
일단은 현재 실행 중인 스레드를 가져와야하므로 thread_current()함수로 불러온다.
그리고 현재 스레드의 interrupt frame도 clone해주어야하기에 스레드 구조체의 멤버인 parent_if에 memcopy해준다.
이제 새로운 프로세스를 만들기 위해 thread_create를 해주고 만들어진 스레드가 __do_fork함수를 실행하도록 한다.
새로 만들어진 프로세스(pintos에서는 단일 스레드이기에 스레드라고 생각해도 됨)가 로드되기 전까지 parent process가 기다려야하기에 fork_sema를 sema_down시킨다.
그러면 이제 기존에 process.c에 존재하는 __do_fork()함수를 reimplement 시켜보자.
먼저, parent process의 스레드 구조체 멤버 parent_if에 저장한 interrupt frame을 user stack에 memcopy시켜준다.
그리고 child process는 fork가 완료된 후 0을 반환받기에 if_.R.rax = 0;를 해준다.
레지스터의 rax부분을 0으로 값을 주면 저 부분을 읽어서 return해주는 느낌으로 생각했다.
다음으로 page table을 clone해주는데 이 부분을 반복해서 봐야겠다.
아직은 어떻게 동작이 되는지 코드만 봐서는 잘 이해가 안간다.
여기까지 마무리됐으면 fork_sema를 sema_up해주어서 parent process가 shceduling될 수 있도록 해주고 do_iret()함수를 이용하여 새로운 프로세스로 context switching 되도록 해준다.
2. int open(const char *file)
open() syscall은 인자로 받은 file이름을 가진 파일을 열어주는 역할을 한다.
성공적으로 open했다면 file decriptor를 반환해주고 실패하면 -1을 리턴한다.
각각의 프로세스는 독립된 file descriptor의 집합을 가지고 있고 이 집합은 fork 시에 child process에게 clone된다.
어떠한 하나의 파일이 한번 이상 open되어도 각각의 open system call은 새로운 file descriptor를 반환한다.
하나의 파일에 대한 서로 다른 file descriptor들은 독립적으로 close system call 호출로 close되고 file descriptor들은 file position을 공유하지 않는다.
위와 같은 open 시스템 콜에 대한 개념을 잡고 구현을 시작해보자.
일단은 check_address를 통해 인자로 받은 file이 user 영역에 있는 주소인지 확인해준다.
그 후에 filesys.c 파일에 있는 filesys_open()함수를 사용하여 인자로 받은 file을 이름으로 가지는 파일 구조체를 가져온다.
구조체를 가져오면 file descriptor table에 file descriptor를 넣어주고 해당 file desciptor를 반환해주면 된다.
3. void close(int fd)
close() 시스템 콜은 인자로 받은 file descritor에 연결된 파일을 닫는 역할을 한다.
프로세스가 종료되었을 때에 모든 open된 file descriptor들을 암묵적으로 닫아줘야한다.
그러면 close 구현을 시작해보자.
일단은 인자로 받은 file descriptor가 가리키고 있는 file 구조체를 찾아줘야한다.
찾는 과정은 현재 실행 중인 스레드를 thread_create()로 불러온 다음에 해당 스레드 구조체 안에 fdTable이라는 fd를 가지고 있는 멤버가 있으므로 인덱스 접근을 하면 찾을 수 있다.
그 후에 해당 fd를 fdTable에서 NULL 처리를 해주고 파일을 닫아주는 작업을 하면 된다.
파일을 닫아주는 작업은 file.c파일에 구현된 file_close()함수를 사용하면 되는데 아직 이 부분을 이해하기에는 file system에 대한 이해도가 부족하다..
4주 때 file system을 공부하고 다시보고 재정리해야겠다.
[오늘의 나는 어땠을까?]
오늘로서 project 2를 마무리 지었다.
project 2를 1.5주동안 보낸 소감은 내일 회고글에 쓰려고 한다.
이제 진짜 3주를 지내면 OS주차가 끝나고 나만의 무기 만들기를 하게 된다.
정글에 들어오면서 다짐했던 마음가짐이 약간 헤이해진 것 같아 스스로에게 꾸짓음을 하고 있는데 얼른 다시 빡집중 모드로 돌아와야한다.
지금 코딩테스트 스터디도 하고 운영체제를 주로 공부하면서 아침 시간에는 HTTP를 공부하면 체계적인 하루를 보내려고 하는데 막상 하루가 지나면 만족스럽지가 않다.
그리고 요즘 내가 좋아하는 농구시즌이 돌아와 하이라이트 영상이 올라오면 참지 못하고 보고 있다.
이런 것도 이제는 참아야한다.
끝까지 달리자.
'기타 > SW 사관학교 정글' 카테고리의 다른 글
[SW 정글 73일차] Pintos project 3 입문 (Virtual Memory) (0) 2021.10.15 SW 정글 9 ~ 10주차 회고 (0) 2021.10.14 [SW 정글 71일차] Pintos project 2 - System Calls 구현 3일차 (0) 2021.10.12 [SW 정글 70일차] Pintos project 2 - System Calls 구현 2일차 (0) 2021.10.12 [SW 정글 69일차] 오늘은 Concurrency 되짚어 보기 (0) 2021.10.11