OS Project2: USER PROGRAMS
Q . user process stack은 어디에서 초기화 되는가?
process_exec 를하면서 load(적재)할때 유저 프로세스의 페이지 테이블 생성
참고 : rsp USER_STACK으로 초기화 된다.
어디서 초기화 되는가? -> thread_create에서 palloc후 init_thread에서 rsp에 값을 집어 넣어주는것으로 확인됨
아래 그림은 레지스터와 interrupt frame 구조체, 레지스터의 쓰임을 보여준다.
File Descriptor
- 목표
파일 디스크립터 및 관련 시스템 콜 구현
- 내용
Pintos에는 파일 디스크립터 부분이 누락되어 있음. 파일 입출력을 위해서는 파일 디스크립터의 구현이 필수
- 해결책
- 파일 디스크립터의 개념을 이해하고 구현 한다.
- 파일 시스템 관련 함수의 사용법을 익힌다.
- 시스템 콜의 요구사항을 분석하고 시스템 콜을 구현 한다.
UNIX의 File Descriptor
- File Descriptor를 통해 파일에 접근
🤔 궁금증 : Process Descriptor Table이란?
출처 : https://subscription.packtpub.com/book/application_development/9781785883057/1/ch01lvl1sec9/process-descriptors
File Descriptor 구현하기
File Descriptor 테이블 추가
- 파일 객체 포인터의 배열 생성
- File Descriptor 등록 시 2부터 순차적으로 File Descriptor 1씩 증가
- open() 시 File Descriptor를 리턴
- close() 시 File Descriptor 테이블에 해당 엔트리 초기화
- 각 프로세스는 자신의 File Descriptor 테이블을 가지고 있음
스레드 생성 시 File Descriptor를 초기화 하도록 수정
tid_t thread_create(const char *name, int priority, thread_func *function, void *aux)
- struct thread에 추가된 필드 초기화
- File Descriptor 테이블 메모리 할당
프로세스 종료 시 열린 파일을 모두 닫도록 수정
void process_exit(void)
- 프로세스 종료가 일어날 경우 프로세스에 열려있는 모든 파일을 닫음
File Descriptor 사용을 위한 함수 추가
int process_add_file(struct file *f)
- 파일 객체에 대한 파일 디스크립터 생성
struct file *process_get_file(int fd)
- 프로세스의 파일 디스크립터 테이블을 검색하여 파일 객체의 주소를 리턴
int process_add_file(struct file *f)
- 파일 디스크립터에 해당하는 파일을 닫고 해당 엔트리 초기화
File Descriptor 테이블 추가
- 파일 객체 포인터의 배열 생성
- 현재 테이블에 할당된 파일 File Descriptor의 최대값 + 1
🤔궁금증
여기서 struct thread* curr = thread_current();
라고 했다면 현재 돌고있는 스레드의 주소를 가리키는게 curr일텐데 만약에
인터럽트를 당해서 현대 쓰레드가 다른 주소로 옮겨졋다면?
문제가 발생한다.
만약 여기서 struct thread* curr이라고해놓고 밑에서 값들을 다바꿔둔뒤
process_add_file이 종료된다면? 그 안에 있는 값들은 다바뀌지만
그 주소는 날라간다.
그래서 항상 thread_current를 정적으로 선언해줄때 이게 data를 공유하는지 아닌지를 계속 생각해서 정적으로 박아두고 쓸지 아니면 thread_current 본연의 그 날것 그 자체를 갖다 쓸것인지 고민해야됨
Q. 페이지 테이블이랑 페이지 디렉토리의 차이?
A. 페이지테이블 :물리메모리 주소를 ~ ? (컴퓨터 시스템의 9장을 읽자)
file_duplicate 함수
pos를 덮어써주는이유 : 부모가 읽은 위치에서 자식이 읽게해야 하니까.
함수 파라미터에 UNUSED를 굳이 써주는이유?
함수 파라미터로 어떤 값을 넘겨받고 그 함수안에서 그 파라미터를 쓰지 않을 경우 보통 컴파일러가 warning(경고) 메시지를 보내주는데 UNUSED를 통해서 경고 메시지를 보내주지 않는다.
✔ Project 2 회고
핀토스 프로젝트 1에 이어 User program 프로젝트 2를 진행하면서 좀 더 운영체제의 입장에서 어떻게 유저 수준과 커널 수준이 나뉘어서 프로세스가 진행 되는지 이해할 수 있었다. 웹 서버 구현할 때도 궁금했던 것이 항상 main 문에서 argc와 **argv를 받아서 정보를 이용하는데, 이런 것들이 어떤 방식으로 받아와 지는지 궁금했었다. 결론적으로 운영체제는 명령어와 인자를 분리하여 그 정보를 이용하여 process를 생성, load하고 유저의 system call을 이용 한다는 사실을 알게 되었다.
-
user가 system call을 호출하면서 인자를 넘길때, 이 인자는 스택포인터를 통해 유저 스택에 정보가 저장되고 커널에서 어셈블리어를 통해 우리가 유저스택을 통해 저장해 놓은 interrupt frame을 따와서 레지스터에 넣어주는 과정을 이해할 수 있었다.
-
레지스터에 인자를 넘겨받으면서 system call interrupt handler를 호출하여 어떻게 system call function을 수행하는지 알 수 있었다.
-
각 system call function은 서로 유기적으로 연결되어 있으면서 특히 부모프로세스와 자식프로세스를 낳는 fork, 프로그램 실행을 위한 exec, 프로세스를 기다리는 wait 함수를 구현하면서 서로간의 confilct를 처리하면서 각 함수들의 동작을 이해할 수 있었다.
이러한 내용들을 이해하고 구현하면서 User program의 전반적인 프로세스를 이해할 수 있었다. 또한 구현을 위해 커널레벨과 유저레벨의 컨텍스트 스위칭 과정을 그림으로 그려보고 코드를 보며 이해하고 구현하면서 머릿속에 각인 시킬 수 있었다.
Author And Source
이 문제에 관하여(OS Project2: USER PROGRAMS), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@wu2ee/OS-Project2-USER-PROGRAMS저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)