[PintOS] Project 2. USER PROGRAMS

🧠·2022년 6월 6일
0

pintos

목록 보기
1/2

들어가기 전


1. Argument Passing

Setup the argument for user program in process_exec()

  • 해당 기능을 구현하기 전에는 새로운 프로세스에 인자를 넘겨주지 못한다.
    ex) 'echo x' 실행시 'echo'라는 프로그램에 'x'라는 인자를 넘겨주어야 하지만 현재 상태는 'echo x'라는 프로그램을 실행시킴

PintOS에서 argument passing

  • /bin/ls -l foo bar 입력시 argument passing 예

코드

  • 6 ~ 11 라인
    - ex) $args-single onearg
  • 유저 프로그램을 실행시킬때 필요한 인자들을 넘겨주기 위해 rsp(코드에선 esp)를 감소시키면서 입력받은 인자들을 스택에 넣어주는 작업
  • argument는 오른쪽부터 스택에 넣는다
  • 13 ~ 18 라인
  • word-align을 위해 8byte 단위로 정렬한다
  • 20 ~ 21 라인
  • argv의 주소입력이 끝났다는 것을 알려주기 위해 0 삽입
  • 23 ~ 26 라인
  • argv 인자들의 주소 입력
  • 28 ~ 29 라인
  • fake "return address" 추가
  • 33 ~ 34 라인
  • argc와 argv 시작 주소를 레지스터에 삽입

2. System Calls

Implement system call infrastructure

PintOS에서 system call 처리의 대략적인 흐름

: )Register
system call number%rax
argument 1%rdi
argument 2%rsi
argument 3%rdx
argument 4%r10
......
  • System Call 호출시 레지스터에 입력되는 값

System Call 구현

0. check_address()

void check_address(void *addr) {
  struct thread *cur = thread_current();
  if (addr == NULL || is_kernel_vaddr(addr) || pml4_get_page(cur->pml4, addr) == NULL)
    exit(-1);
}
  • 인자로 들어온 addr 값이 NULL인지
  • 커널 영역의 주소인지
  • 페이지가 할당된 상태인지

3가지 상황을 확인하여 하나라도 해당하면 exit(-1) 호출

1. halt()

void halt(void) {
  // * power_off()를 사용하여 pintos 종료
  power_off();
}

2. exit()

  1. exit() syscall 호출
  2. 프로세스 종료 메시지 출력 후 thread_exit() 호출
  3. thread_exit()에서 process_exit()을 호출
  4. process_exit()에서 열려있던 파일들을 다 닫고 부모의 exit_sema UP 신호를 기다림
  5. 부모가 exit_sema를 up해주면 fdt에 할당받은 페이지들을 반납하고 종료
void exit(int status) {
  /*
   * 실행중인 스레드 구조체를 가져와 exit_status 값 수정
   * 프로세스 종료 메시지 출력
   * 출력 양식: "프로세스 이름: exit(종료상태)"
   * thread 종료
   */ 
  struct thread *cur = thread_current();
  cur->exit_status = status;
  printf("%s: exit(%d)\n", cur->name, status);
  thread_exit();
}

/* Exit the process. This function is called by thread_exit (). */
void
process_exit (void) {
	struct thread *curr = thread_current ();
    struct file **table = curr->fdt;
	/* TODO: Your code goes here.
	 * TODO: Implement process termination message (see
	 * TODO: project2/process_termination.html).
	 * TODO: We recommend you to implement process resource cleanup here.
     */
  
	if (curr->run_file)
		file_close(curr->run_file);

	int cnt = 2;
	while (cnt < 128) {
		if (table[cnt]) {
			file_close(table[cnt]);
			table[cnt] = NULL;
		}
		cnt++;
  	}
	
    struct list_elem *e;
	struct thread *ch;

	sema_up(&curr->load_sema);
	// * 부모 thread로 부터 죽어도 된다는 신호가 올때까지 대기하고 있어야 함
	sema_down(&curr->exit_sema);

	palloc_free_page(table);
	process_cleanup ();
}

3. fork()

  1. fork() syscall 호출
  2. syscall handler로 넘겨받은 intr_fram f를 현재 스레드의 ptf에 저장
  3. process_fork() 함수를 통해 자식 스레드 생성 후 자식 스레드는 __do_fork() 함수 실행
  4. 자식 스레드 if에 syscall handler에서 저장했던 부모 스레드의 ptf를 넘김
  5. 자식 스레드의 fork 리턴값은 0이므로 'if_R.rax = 0'
  6. 부모 스레드의 파일테이블을 모두 복사

int fork (const char *thread_name) {
  check_address(thread_name);
  return process_fork(thread_name, &thread_current()->ptf);
}
tid_t
process_fork (const char *name, struct intr_frame *if_ UNUSED) {
	/* Clone current thread to new thread.*/
  struct thread *cur = thread_current();
  tid_t ctid = thread_create (name, PRI_DEFAULT, __do_fork, cur);
  if (ctid == TID_ERROR)
    return TID_ERROR;
  sema_down(&cur->fork_sema);
  return ctid;
}

fork()에서 intr_frame에 관한 더 자세한 내용은 Debug Choi 블로그를 참고하면 된다.

4. create()

bool create (const char *file, unsigned initial_size) {
  /* 
   * 파일 이름과 크기에 해당하는 파일 생성
   * 파일 생성 성공 시 true 반환, 실패 시 false 반환
   */
  check_address(file);
  return filesys_create(file, initial_size);
}

5. remove()

bool remove (const char *file) {
  /* 
   * 파일 이름에 해당하는 파일을 제거
   * 파일 제거 성공 시 true 반환, 실패 시 false 반환
   */
  check_address(file);
  return filesys_remove(file);
}

6. open()

  1. open() syscall 호출
  2. filesys_open 함수를 통해 파일을 열어 fd에 저장
  3. 현재 스레드의 fdt에 추가하고 fdt에 저장된 파일이 128개가 넘었다면 다시 close (더 이상 파일 open이 불가능한 상태)
  4. 만약 파일 열기에 실패했다면 -1을 리턴
int open (const char *file) {
  check_address(file);
  struct thread *cur = thread_current();
  struct file *fd = filesys_open(file);
  if (fd) {
    for (int i = 2; i < 128; i++) {
      if (!cur->fdt[i]) {
        cur->fdt[i] = fd;
        return i;
      }
    }
    file_close(fd);
  }
  return -1;
}

7. filesize()

int filesize (int fd) {
  struct file *file = thread_current()->fdt[fd];
  if (file)
    return file_length(file);
  return -1;
}

8. read()

  1. read() syscall 호출
  2. stdin에 read를 요청시 input_getc() 함수 활용
  3. 그 외 파일은 file_read 함수를 통해 파일에서 버퍼 사이즈 만큼 read
  4. 다른 프로세스가 파일을 사용하고 있을 수 있으니 lock을 활용
  5. 만약 파일 읽기에 실패했다면 -1을 리턴
int read (int fd, void *buffer, unsigned size) {
  check_address(buffer);
  if (fd == 1) {
    return -1;
  }

  if (fd == 0) {
    lock_acquire(&filesys_lock);
    int byte = input_getc();
    lock_release(&filesys_lock);
    return byte;
  }
  struct file *file = thread_current()->fdt[fd];
  if (file) {
    lock_acquire(&filesys_lock);
    int read_byte = file_read(file, buffer, size);
    lock_release(&filesys_lock);
    return read_byte;
  }
  return -1;
}

9. write()

int write (int fd UNUSED, const void *buffer, unsigned size) {
  check_address(buffer);

  if (fd == 0) // STDIN일때 -1
    return -1;

  if (fd == 1) {
    lock_acquire(&filesys_lock);
	  putbuf(buffer, size);
    lock_release(&filesys_lock);
    return size;
  }

  struct file *file = thread_current()->fdt[fd];
  if (file) {
    lock_acquire(&filesys_lock);
    int write_byte = file_write(file, buffer, size);
    lock_release(&filesys_lock);
    return write_byte;
  }
}

10. exec()

int exec (const char *file_name) {
  check_address(file_name);

  int file_size = strlen(file_name) + 1;
  char *fn_copy = palloc_get_page(PAL_ZERO);
  if (!fn_copy) {
    return -1;
  }
  strlcpy(fn_copy, file_name, file_size);
  if (process_exec(fn_copy) == -1) {
    return -1;
  }
}

11. seek()

void seek (int fd, unsigned position) {
  struct file *curfile = thread_current()->fdt[fd];
  if (curfile)
    file_seek(curfile, position);
}

12. tell()

unsigned tell (int fd) {
  struct file *curfile = thread_current()->fdt[fd];
  if (curfile)
    return file_tell(curfile);
}
profile
: )

0개의 댓글