운영체제(OS)/with PintOS

(Project2-User Programs) - Extend File Descriptor (Extra)

스탠딩 2023. 12. 26. 21:22

Extend File Descriptor (Extra)

리눅스에서 stdin, stdout 및 dup2 시스템 호출 종료를 지원하도록 핀토스 만들기

현재 핀토스의 구현에서는 stdin과 stdout의 fd를 닫는 것이 금지되어 있습니다. 이 추가 점수 요구 사항에서는 먼저 사용자가 리눅스와 동일하게 stdin과 stdout을 닫을 수 있도록 허용합니다. 즉, 사용자가 stdin을 닫으면 프로세스가 입력을 읽지 않아야 하고, stdout을 닫으면 프로세스가 아무것도 출력하지 않아야 합니다.

다음으로 dup2 시스템 호출을 구현합니다.

int dup2(int oldfd, int newfd);

dup2() 시스템 호출은 newfd에 지정된 파일 기술자 번호로 파일 기술자 oldfd의 복사본을 생성하고 성공하면 newfd를 반환합니다. 파일 기술자 newfd가 이전에 열려 있었다면 재사용되기 전에 자동으로 닫힙니다.

다음 사항에 유의하세요:

  • oldfd가 유효한 파일 기술자가 아닌 경우 호출이 실패하고(-1을 반환) newfd가 닫히지 않습니다.
  • oldfd가 유효한 파일 기술자이고 newfd의 값이 oldfd와 같으면 dup2()는 아무 작업도 수행하지 않고 newfd를 반환합니다.

이 시스템 호출에서 성공적으로 반환된 후에는 이전 파일 기술자와 새 파일 기술자를 서로 바꿔서 사용할 수 있습니다. 서로 다른 파일 기술자이지만 동일한 열린 파일 설명을 참조하므로 파일 오프셋과 상태 플래그를 공유합니다. 예를 들어, 기술자 중 하나에서 seek를 사용하여 파일 오프셋이 수정되면 다른 파일에 대해서도 오프셋이 변경됩니다.

 

case SYS_DUP2:
        SET_RAX(f, sys_dup2((int)args[0], (int)args[1]));
        break;

 

int sys_dup2(int oldfd, int newfd)
{
    struct thread *cur_thread = thread_current();
    void *old_f = process_get_file(oldfd);

    if (old_f == NULL)
        return -1;

    if (newfd < 0)
        return -1;

    if (oldfd == newfd)
        return newfd;

    // extend fd table if required (newfd >= cur_thread->next_fd)
    if (newfd >= cur_thread->next_fd)
    {
        void *old_fd_table = cur_thread->fd_table;
        cur_thread->fd_table = (struct file **)realloc(cur_thread->fd_table, sizeof(struct file *) * (newfd + 1));
        if (cur_thread->fd_table == NULL)
        {
            cur_thread->fd_table = old_fd_table;
            sys_exit(-1);
        }

        for (int i = cur_thread->next_fd; i <= newfd; i++)
            cur_thread->fd_table[i] = NULL;

        cur_thread->next_fd = newfd + 1;
    }

    // close newfd contents
    if (process_get_file(newfd) != NULL)
        process_close_file(newfd);

    cur_thread->fd_table[newfd] = cur_thread->fd_table[oldfd];

    return newfd;
}