08_week_C_pintos_systemcall-2

신치우·2022년 11월 28일
0

data_structure_and_Pintos

목록 보기
22/36

여기서부터는 system call을 구현할 예정이다
(halt, exit, wait, close, create, remove, seek, tell)

syscall을 구현하기 전에 pml4 에 빨간줄이 계속 생겨서 불편하다면 아래와 같은 방법으로 해결하면된다. (Ctrl + shift + P) C/C++: 구성편집 UI로 들어간다

--> 이후 정의 탭에 USERPROG를 쓰고 꺼주면된다 (자동저장)

system call 구현

수정할 파일 : syscall.c, sycall.h, thread.c, thread.h, exception.c

먼저 system_call handler 에서 받은 frame 정보를 구분해준다 (switch를 사용하기 위해)

이후 switch 문을 만들어서 들어오는 syscall_no을 통해서 함수를 태운다

 switch (syscall_no) {   // return 을 시켜주는 handler들은 f->R.rax로 return을 시켜줘야함 (다음 syscall_no을 동작시켜야함)
    case SYS_HALT:   // poawer off system call
      halt_handler ();
      break;
    case SYS_EXIT:   // exit system call
      exit_handler (a1);
      break;
    case SYS_FORK:   // fork system call - 자식 process를 만든다
      f->R.rax = fork_handler (a1, f);
      break;
    case SYS_EXEC:   // exec system call
      f->R.rax = exec_handler (a1);
      break;
    case SYS_WAIT:
      f->R.rax = wait_handler (a1);
      break;
    case SYS_CREATE:
      f->R.rax = create_handler (a1, a2);
      break;
    case SYS_REMOVE:
      f->R.rax = remove_handler (a1);
      break;
    case SYS_OPEN:
      f->R.rax = open_handler (a1);
      break;
    case SYS_FILESIZE:
      f->R.rax = file_size_handler (a1);
      break;
    case SYS_READ:
      f->R.rax = read_handler (a1, a2, a3);
      break;
    case SYS_WRITE:
      f->R.rax = write_handler (a1, a2, a3);
      break;
    case SYS_SEEK:
      seek_handler (a1, a2);
      break;
    case SYS_TELL:
      f->R.rax = tell_handler (a1);
      break;
    case SYS_CLOSE:
      close_handler (a1);
      break;

    default:
      exit_handler (-1);
      break;
  }

먼저 선언하는 두가지 함수는 지속적으로 handler 를 구현하면서 지속적으로 사용하게됨
1. check_add -- input 받은 address가 user 영역인지 확인하는 작업
==> gitbook의 User Memory Access 와 관련된 부분

void
check_add (void *add) {
  struct thread *cur = thread_current ();
  if (!is_user_vaddr (add) || add == NULL ||
      pml4_get_page (cur->pml4, add) == NULL) {
    exit_handler (-1);
  }
}
  1. find_file_using_fd - fd를 이용하여 file을 찾는 함수
static struct file *
find_file_using_fd (int fd) {   // fd를 가지고 file을 찾기 위한 함수 file은
                                // process에 저장되어있으니 찾는거 가능
  struct thread *cur = thread_current ();

  if (fd < 0 || fd >= FD_COUNT_LIMT)
    return NULL;

  return cur->fd_table[fd];   // 해당 file을 return 함
}
  1. filesys의 함수를 사용할때 interrupt를 막기위한 lock이 필요함
// syscall.h
struct lock filesys_lock; // write 사용시에 나만 작성하기 위해서 lock을 사용

syscall_init() 안에서 lock을 init 해줌

lock_init (&filesys_lock);   // write 시에 다른 접근이 오는걸 막기위해 lock을 사용
  1. thread 내부에 필요한 선언
//thread.h - struct thread 안에
  int exit_status; // 현재 파일의 status를 확인하기 위해서
  struct file **fd_table; // 프로세서는 파일 디스크립터를 관리하는 테이블이 필요함
  int fd_idx; // 그리고 그 파일 디스크립터 테이블에 들어가는 파일 디스크립터의 인덱스를 저장

  struct list child_s; // 부모가 자식 process의 정보를 기억할 공간
  struct list_elem child_elem; // child list elem
  
  struct intr_frame parent_if; // 부모의 intr_frame 정보를 기억할 공간
  struct semaphore fork_sema; // 자식이 fork가 완료 될때까지 기다리는 sema
  struct semaphore wait_sema; // process 가 동작중일땐 wait에서 대기를 해야만함 --> exit가 들어오기 전까지는 계속 대기
  struct semaphore exit_sema; // exit handler를 위한 sema --> 종료가 되기전에 wait와 fork 쪽이 먼저 정리가 되어야하니깐

  struct file *running; // rox를 위해 사용할 공간
// thread.c --> init_thread() 함수 안에
  /* for project -2 start */
  // project 2 에서 선언된 애들을 init 해줌
  list_init(&t->child_s); 
  sema_init(&t->fork_sema,0);
  sema_init(&t->wait_sema,0);
  sema_init(&t->exit_sema,0); 
  
  /* for project -2 end */
// thread.c --> tid_t thread_create() 안에
  // 2중 포인터 부분은 init 함수를 사용하지 못하기 때문에 fd_table 아래와 같이 새로 할당 받음
  t->fd_table = palloc_get_multiple(PAL_ZERO, FD_PAGES);
  if (t->fd_table == NULL)
    return TID_ERROR;
  
  // 0, 1 두개의 공간은 정해진 역할을 해야함 따라서 index (fd의 개수) 는 2부터 시작함
  t->fd_table[0]=1; // stdin 자리
  t->fd_table[1]=2; // stdout 자리
  t->fd_idx = 2;

  struct thread *cur = thread_current();
  list_push_back(&cur->child_s, &t->child_elem); // create 할 때 자기 자신을 자식 process list에 넣어줌

  cur->exit_status =0; // 종료 status를 초기 0으로 초기화

gitbook 내용
0번 파일식별자와 1번 파일식별자는 이미 역할이 지정되어 있습니다. 0번은 표준 입력(STDIN_FILENO)을 의미하고 1번은 표준 출력(STDOUT_FILENO)을 의미합니다.

halt

pintos 자체를 종료시키는 부분 (power_off() 는 사전에 구현된 함수)

//syscall.c
void
halt_handler (void) {   // Pintos를 종료시킴
  power_off ();
}

wait

//syscall.c
int
wait_handler (tid_t pid) {   // 자식 process를 wait 함 (exit status가 올때까지)
  return process_wait (pid);
}
//process.c

int
process_wait (tid_t child_tid UNUSED) {
  /* XXX: Hint) The pintos exit if process_wait (initd), we recommend you
   * XXX:       to add infinite loop here before
   * XXX:       implementing the process_wait. */

  struct thread *child = get_child (child_tid); // 해당 tid를 갖는 child를 찾고
  if (child == NULL)
    return -1;
  sema_down (&child->wait_sema); // process 의 wait를 sema down함 --> process는 현재 동작 중이고 wait에서 대기중임
  list_remove (&child->child_elem); // 얘를 삭제한다는 것은 process exit 신호가 들어왔음을 의미함 (process_exit에서 sema up을 시켜줌)
  sema_up (&child->exit_sema); // 삭제 후 sema_up으로 child exit_sema도 풀어줌

  return child->exit_status;
}

get_child는 fd를 이용하여 child를 찾고 해당 child를 thread 형태로 return 함

struct thread *
get_child (int pid) {   // child process를 찾는 함수 -- child list를 관리하니깐
                        // 거기서 찾으면됨
  struct thread *cur = thread_current ();
  struct list *child_list = &cur->child_s; // 현재 process의 자식 process list

  for (struct list_elem *temp = list_begin (child_list); temp != list_end (child_list); temp = list_next (temp)) { // 자식 process의 list를 순회하면서 자식는 부분
    struct thread *temp_thread = list_entry (temp, struct thread, child_elem);

    if (temp_thread->tid == pid) {
      return temp_thread;
    }
  }
  return NULL;   // 만일 적합한 child를 찾지 못했다면 NULL 을 return함
}

close

file_close 는 사전에 구현되어 있는 함수

//syscall.c

void
close_handler (int fd) {   // fd를 이용하여 열려 있는 file을 닫음
  struct file *file_obj = find_file_using_fd (fd);
  if (file_obj == NULL)
    return;

  if (fd < 0 || fd >= FD_COUNT_LIMT)
    return;
  thread_current ()->fd_table[fd] = NULL;   // 열린 파일이 있던 위치를 NULL로 바꾸고

  lock_acquire (&filesys_lock);
  file_close (file_obj);
  lock_release (&filesys_lock);
}

exit

process를 종료시킨다 -- 하지만 자식 process가 살아있다면 자식 process가 종료될 때까지 기다려야함

//syscall.h

void
exit_handler (int status) {   // 현재 동작중인 program을 종료함
  struct thread *cur = thread_current ();
  cur->exit_status = status;   // exit status를 저장해주고 종료
  printf ("%s: exit(%d)\n", cur->name, status);
  thread_exit (); // thread exit 안에 process exit가 있음
}
//process.c
void
process_exit (void) {
  struct thread *curr = thread_current ();
  /* 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. */

  for (int i = 2; i < FD_COUNT_LIMT; i++) // process가 끝나는 신호가 들어오면 해당 process에서 열려있던 file들을 모두 닫아줌
    close_handler (i); 

  palloc_free_multiple (curr->fd_table, FD_PAGES);   // thread create때 할당 받은 공간을 다시 free해줌
  file_close (curr->running);  // ROX 를 위한 부분 (write deny가 된걸 file close 해주면 해당 함수 안에 allow로 해제 해주는 부분도 존재함)
  process_cleanup ();   // 현재 process의 자원도 해제해줘야함 --> 이게 sema down 밑으로 가면 sema _down에서 동작하지 않아서 multi-oom 이 실패함

  sema_up (&curr->wait_sema); // exit 신호를 받았기 때문에 wait_sema를 올려주고 wait에 걸려있던 process가 종료하게됨
  sema_up (&curr->fork_sema); // fork_sema 도 해제해줌 --> 다 종료해야하니깐 (sema가 걸려있으면 삭제도 종료도 안되니깐)
  sema_down (&curr->exit_sema); // 이후 exit는 wait가 끝난 이후에 종료가 되어야하니깐 exit sema를 down해서 걸어놓음
}

create

filesys_create 는 사전에 구현되어 있는 함수

// syscall.c
bool   // create 성공하면 true 실패하면 false, ++ open 이랑은 다른것, 혼란스러워하면 안됨
create_handler (const char *file, unsigned initial_size) {
  check_add (file);
  return filesys_create (file, initial_size);
}

remove

filesys_remove 는 사전에 구현되어 있는 함수

//syscall.c
bool   // remove 성공하면 true 실패하면 false, ++ file이 remove되는 것과 close는 별개임 (즉, 제거되더라도 open되어있을 수도 있다는 말)
remove_handler (const char *file) {
  check_add (file);
  return (filesys_remove (file));
}

seek

file_seek 는 사전에 구현되어 있는 함수

//syscall.c
void
seek_handler (int fd, unsigned position) {   // file 내부의 커서를 이동한다 --> 첫 시작은 position이 0이고 끝까지 가면 file의 크기와 같은 byte를 가짐
  struct file *file_obj = find_file_using_fd (fd);

  file_seek (file_obj, position);   // 만약 position이 파일의 끝을 가리키고 있는데 더 position을
                                    // 찾는걸 요청한다면 커서는 파일 끝을 가리키지만 byte는 읽은
                                    // 바이트가 없기 때문에 0을 나타냄
}

tell

file_tell 은 사전에 구현되어 있는 함수

//syscall.c
unsigned
tell_handler (int fd) {   // file의 read or write를 하기 위한 위치를 반환함 - byte로
  if (fd <= 2)
    return;
  struct file *file_obj = find_file_using_fd (fd);
  check_add (file_obj);
  if (file_obj == NULL)
    return;

  return file_tell (file_obj);
}
profile
하루에 집중을

0개의 댓글

관련 채용 정보