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에는 파일 디스크립터 부분이 누락되어 있음. 파일 입출력을 위해서는 파일 디스크립터의 구현이 필수
  • 해결책
    1. 파일 디스크립터의 개념을 이해하고 구현 한다.
    2. 파일 시스템 관련 함수의 사용법을 익힌다.
    3. 시스템 콜의 요구사항을 분석하고 시스템 콜을 구현 한다.

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을 이용 한다는 사실을 알게 되었다.

  1. user가 system call을 호출하면서 인자를 넘길때, 이 인자는 스택포인터를 통해 유저 스택에 정보가 저장되고 커널에서 어셈블리어를 통해 우리가 유저스택을 통해 저장해 놓은 interrupt frame을 따와서 레지스터에 넣어주는 과정을 이해할 수 있었다.

  2. 레지스터에 인자를 넘겨받으면서 system call interrupt handler를 호출하여 어떻게 system call function을 수행하는지 알 수 있었다.

  3. 각 system call function은 서로 유기적으로 연결되어 있으면서 특히 부모프로세스와 자식프로세스를 낳는 fork, 프로그램 실행을 위한 exec, 프로세스를 기다리는 wait 함수를 구현하면서 서로간의 confilct를 처리하면서 각 함수들의 동작을 이해할 수 있었다.

이러한 내용들을 이해하고 구현하면서 User program의 전반적인 프로세스를 이해할 수 있었다. 또한 구현을 위해 커널레벨과 유저레벨의 컨텍스트 스위칭 과정을 그림으로 그려보고 코드를 보며 이해하고 구현하면서 머릿속에 각인 시킬 수 있었다.

좋은 웹페이지 즐겨찾기