1227-TIL

그로밋·2023년 12월 27일
0

krafton jungle

목록 보기
53/58

Stack growth

스택그로스는 이 레퍼런스를 참고해서 구현했더니 바로 관련 테스트케이스가 통과했다.

다만 조건문중에 아주 복잡한 부분이 있어서 짚고 넘어갔다.

스택 확장으로 처리할 수 있는 폴트인 경우를 표현하기 위해 (USER_STACK - (1 << 20) <= rsp - 8 && rsp - 8 == addr && addr <= USER_STACK) 이렇게 된 모습이다.

연산자 우선순위에 의해서

  1. 1 << 20: 비트 왼쪽 시프트 연산은 가장 높은 우선순위를 갖는데, 이는 1을 20만큼 왼쪽으로 비트 이동시키는 연산입니다.
  2. USER_STACK - (1 << 20): 뺄셈 연산은 비트 시프트 연산보다 우선순위가 낮습니다. 따라서 USER_STACK에서 (1 << 20)을 뺀 값이 계산됩니다.
  3. rsp - 8: 뺄셈 연산은 비트 시프트 연산보다 우선순위가 낮기 때문에, rsp에서 8을 뺀 값이 계산됩니다.
  4. addr == rsp - 8: 비교 연산은 뺄셈보다 우선순위가 높으므로, rsp - 8과 addr이 같은지 비교합니다.
  5. USER_STACK - (1 << 20) <= rsp - 8: 이전 단계에서 계산된 값과 USER_STACK - (1 << 20)을 비교합니다.
  6. addr <= USER_STACK: 비교 연산은 뺄셈보다 우선순위가 높으므로, addr과 USER_STACK을 비교합니다.
  7. 마지막으로 논리 AND (&&) 연산자를 사용하여 앞선 모든 비교를 연결합니다.

현재 전체 테스트케이스 결과 모습


특이 케이스 처리

아래의 특수 테스트 케이스를 해결해야 한다.

FAIL tests/vm/pt-write-code2
FAIL tests/vm/pt-grow-stk-sc

이건 동료 document 의 도움을 받아 해결했다.

현재까지 상황 27 of 141 tests failed.

page-merge-seq
page-merge-par
page-merge-stk

이 세개 fail 떴었다가 다시 돌리니까 두개 fail 뜬다...

왜이럴까? 일단 제쳐두고 mmap하자.

Memory Mapped Files

syscall_handelr()

mmap()

void *mmap(void *addr, size_t length, int writable, int fd, off_t offset) {
    if (!addr || addr != pg_round_down(addr)) return NULL;  // addr 없는 경우

    if (offset != pg_round_down(offset))
        return NULL;  // offset이 page aligned 되지 않은 경우

    if (!is_user_vaddr(addr) || !is_user_vaddr(addr + length))
        return NULL;  // addr이 user 영역이 아닌 경우

    if (spt_find_page(&thread_current()->spt, addr))
        return NULL;  // spt에 있는 경우

    struct file *f = process_get_file(fd);
    if (f == NULL) return NULL;  // file이 없는 경우

    if (file_length(f) == 0 || (int)length <= 0)
        return NULL;  // file의 길이가 0 혹은 음수인 경우

    return do_mmap(addr, length, writable, f,
                   offset);  // 파일이 매핑된 가상 주소 반환
}

do_mmap()

매핑을 진행할 때는 간단하게 (페이지 주소 addr + PGSIZE에 위치하는) 다음 페이지에 이어서 매핑하면 되지만, 매핑을 해제할 때는 몇 번째 페이지까지 해제해야 하는지를 알아야 한다. 따라서 총 몇 페이지를 사용해서 매핑이 이루어졌는지에 대한 정보도 page 구조체에 함께 저장해 둔다. 출처

void *do_mmap(void *addr, size_t length, int writable, struct file *file,
              off_t offset) {
    struct file *f = file_reopen(file);
    // this is for returning mapped virtual address when the mapping is suceeded
    void *start_addr = addr;
    // Total number of page for mapping
    int total_page_count = length <= PGSIZE  ? 1
                           : length % PGSIZE ? length / PGSIZE + 1
                                             : length / PGSIZE;

    size_t read_bytes = file_length(f) < length ? file_length(f) : length;
    size_t zero_bytes = PGSIZE - read_bytes % PGSIZE;

    ASSERT((read_bytes + zero_bytes) % PGSIZE == 0);
    ASSERT(pg_ofs(addr) == 0);     // page alignment for the upage
    ASSERT(offset % PGSIZE == 0);  // page alignment for the ofs

    while (read_bytes > 0 || zero_bytes > 0) {
        /* 이 페이지를 채우는 방법을 계산합니다.
        파일에서 PAGE_READ_BYTES 바이트를 읽고
        최종 PAGE_ZERO_BYTES 바이트를 0으로 채웁니다. */
        size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE;
        size_t page_zero_bytes = PGSIZE - page_read_bytes;

        struct lazy_load_arg *lazy_load_arg =
            (struct lazy_load_arg *)malloc(sizeof(struct lazy_load_arg));
        lazy_load_arg->file = f;
        lazy_load_arg->ofs = offset;
        lazy_load_arg->read_bytes = page_read_bytes;
        lazy_load_arg->zero_bytes = page_zero_bytes;

        // vm_alloc_page_with_initializer를 호출하여 대기 중인 객체를
        // 생성합니다.
        if (!vm_alloc_page_with_initializer(VM_FILE, addr, writable,
                                            lazy_load_segment, lazy_load_arg))
            return NULL;

        struct page *p = spt_find_page(&thread_current()->spt, start_addr);
        p->mapped_page_count = total_page_count;

        /* Advance. */
        // 읽은 바이트와 0으로 채운 바이트를 추적하고 가상 주소를 증가시킵니다.
        read_bytes -= page_read_bytes;
        zero_bytes -= page_zero_bytes;
        addr += PGSIZE;
        offset += page_read_bytes;
    }

    return start_addr;
}

Trouble shooting

mmap-read, overlap

위 테케 포함 중간중간 mmap 관련 테스트 실패

try

syscall.c 의 syscall_handler에서
SYS_MMAP에서 mmap함수 결과를 rax 레지스터에 담았다

before

after


현재상황

mmap-inherit 빼고 mmap 관련 테케 성공

profile
Work as though your strength were limitless. <S. Bernhardt>

0개의 댓글