크래프톤 정글/pintOS

pintOS - project2(Userprog) process.c

문미새 2024. 3. 30. 23:05
728x90

process.c

 

< argument_stack >

더보기
// 명령줄 인자를 스택에 배치한다.
void argument_stack (char **argv, int argc, struct intr_frame *if_){
	
	int minus_addr;
	int address = if_->rsp; // 스택 포인터(rsp)의 현재 위치를 담는다.
    
    // 인자를 거꾸로 넣기 위해 마지막부터 루프
	for (int i = argc-1; i >= 0;i-- ){
    	// 현재 인자의 길이 + '\0'(1개)를 minus_addr에 저장
		minus_addr = strlen(argv[i]) + 1; //if onearg, value = 7 
		address -= minus_addr; // 인자 크기만큼 address를 감소시켜 저장공간을 확보한다.
		memcpy(address, argv[i], minus_addr); // 현재 인자를 스택에 복사
		argv[i] = (char *)address; // 배열 내 해당 인자의 포인터를 스택에 복사된 인자 위치로 변경
	}

	// 주소값을 8로 나눠 나머지가 있으면(8바이트로 정렬되어있는지 확인)
	if (address % 8){
		int word_align = address % 8; // 나머지를 word_align에 넣고
		address -= word_align; // 주소에서 나머지만큼 뺀다.
		memset(address, 0, word_align); // 정렬을 위해 추가된 공간을 0으로 채운다.
	}

	address -= 8; // 주소 값을 8을 빼 공간을 확보한다.
	memset(address, 0, sizeof(char*)); // 배열의 시작부분에 널포인터 삽입

	address -= (sizeof(char*) * argc); // 인자 포인터들을 저장할 충분한 공간을 만든다.
	memcpy(address, argv, sizeof(char*) * argc); // 인자 포인터 배열을 스택에 복사한다.

	address -= 8; // 리턴 주소를 위해 공간을 확보한다.
	memset(address, 0, 8); // 리턴 주소 공간을 0으로 초기화한다.
	if_->rsp = address; // 스택 포인터에 주소값을 넣는다.
}

 

< process_create_initd >

더보기
// 프로세스를 생성하고 초기화한다.
tid_t
process_create_initd (const char *file_name) {
	char *fn_copy;
	tid_t tid;

	/* FILE_NAME의 복사본을 만듭니다.
	 * 그렇지 않으면 발신자와 load() 사이에 경합이 발생합니다. */
	fn_copy = palloc_get_page (PAL_USER);
	if (fn_copy == NULL)
		return TID_ERROR;
	strlcpy (fn_copy, file_name, PGSIZE);

	// 스페이스 전 첫 부분을 실행하고자 하는 파일의 이름으로 지정 (argument passing)
	char *save_ptr;
	strtok_r (file_name, " ", &save_ptr);

	// 새 스레드를 생성하여 FILE_NAME을 실행
	tid = thread_create (file_name, PRI_DEFAULT, initd, fn_copy);

	// tid가 TID_ERROR라면(할당이나 생성 과정에서 오류 발생)
	if (tid == TID_ERROR) {
		palloc_free_page (fn_copy); // 복사본을 할당해제한다.
		palloc_free_page (file_name); // 파일도 할당해제한다.
	}
    
    // TID_ERROR라면 tid에 에러를 넣고 아니면 tid를 넣기 
	return tid == TID_ERROR ? TID_ERROR : tid;
}

 

< initd >

더보기
// 처음 프로세스를 시작할 때 초기화한다.
static void
initd (void *f_name) {
// VM 부분은 아직 안봐도 된다.
#ifdef VM
	supplemental_page_table_init (&thread_current ()->spt);
#endif
	// 현재 스레드를 실행해서 0 미만이라면(에러) PANIC을 일으킨다.
	process_init ();
	if (process_exec (f_name) < 0)
		PANIC("Fail to launch initd\n");
	NOT_REACHED (); // 도달할 수 없다는 뜻
}

 

< process_fork >

더보기
/* 현재 프로세스를 'name'으로 복제합니다. 새 프로세스의 스레드 ID를 반환하거나
 * 스레드를 만들 수 없는 경우 TID_ERROR입니다. */
tid_t
process_fork (const char *name, struct intr_frame *if_) {
	/* 현재 스레드를 새 스레드로 복제한다.*/
	struct parent_info my_data;
	my_data.parent = thread_current();
	my_data.parent_f = if_;

	struct thread *cur = thread_current();
	memcpy(&cur->parent_tf, my_data.parent_f , sizeof(struct intr_frame));

	// __do_fork 함수를 이용해 스레드를 생성한다.
	tid_t tid = thread_create(name, PRI_DEFAULT, __do_fork, &my_data);
    
    // 생성에 실패시 TID_ERROR 반환
	if (tid == TID_ERROR){
		return TID_ERROR;
	}

	struct thread *child = get_thread_from_tid(tid); // 인자인 tid를 가진 스레드를 가져와 child에 저장
	sema_down(&child->process_sema); // 동시성 문제를 위해 세마를 감소시켜 블락상태로 유지
    
    // 가져온 스레드의 exit_status가 생성 에러라면 감소시킨 세마를 다시 증가시키고 에러 반환
	if(child->exit_status == TID_ERROR)
	{
		sema_up(&child->exit_sema);
		
		return TID_ERROR;
	}

	// 오류가 아니라면 tid를 반환
	return tid;
}

 

< duplicate_pte >

더보기
// 이 함수를 다음에 전달하여 부모 주소 공간을 복제한다.
static bool
duplicate_pte (uint64_t *pte, void *va, void *aux) {
	struct thread *current = thread_current ();
	struct thread *parent = (struct thread *) aux;
	void *parent_page;
	void *newpage;
	bool writable;

	// 부모 페이지가 커널 페이지인 경우 true 반환
	if (is_kernel_vaddr(va)){
		return true;
	}

	// 상위 페이지 맵 레벨 4에서 VA를 해경해 parent_page에 넣고 없으면 false 반환
	parent_page = pml4_get_page (parent->pml4, va);
	if (parent_page == NULL){
		return false;
	}

	// 자식에 새 PAL_USER 페이지를 할당하고 결과를 NEWPAGE로 설정하고 없으면 false 반환
	newpage = palloc_get_page(PAL_USER);
	if (newpage == NULL){
		return false;
	}

	/* 부모 페이지를 새 페이지에 복제하고 부모 페이지가 쓰기 가능한지 여부를 확인
    (결과에 따라 쓰기 가능으로 설정). */
	memcpy(newpage, parent_page, PGSIZE);
	writable = is_writable(pte);

	/* 5. 쓰기 가능한 권한으로 주소 VA의 어린이 페이지 테이블에 새 페이지를 추가 */
	if (!pml4_set_page (current->pml4, va, newpage, writable)) {
		/* 6. 작업: 페이지를 삽입하지 못할 경우 오류 처리를 수행 */
		return false;
	}
	return true;
}

 

< __do_fork >

더보기
 /* 부모의 실행중인 프로세스의 복사본을 생성한다.
 * parent->tf는 프로세스의 사용자 및 컨텍스트를 유지하지 않는다.
 * 즉, process_fork의 두 번째 인수를 이 함수에 전달해야 함 */
static void
__do_fork (struct parent_info *aux) {
	struct intr_frame if_;
	struct thread *parent = aux->parent;
	struct thread *current = thread_current ();
	struct intr_frame *parent_if = aux->parent_f;

	bool succ = true;

    // CPU 컨텍스트를 로컬 스택으로 읽는다.
    memcpy(&if_, parent_if, sizeof(struct intr_frame));
    if_.R.rax = 0; // 자식 프로세스의 리턴값은 0

    // 자식 프로세스를 위한 새로운 페이지 테이블을 생성한다. 없으면 error로 점프
    current->pml4 = pml4_create();
    if (current->pml4 == NULL)
        goto error;

	// 자식 프로세스를 활성화한다.
    process_activate(current);
// VM은 project3이라 지금은 필요없다.
#ifdef VM
    supplemental_page_table_init(&current->spt);
    if (!supplemental_page_table_copy(&current->spt, &parent->spt))
        goto error;
#else
	/* 부모 페이지 테이블의 모든 엔트리를 순회해 duplicate_pte함수를 실행하여
    자식 프로세스 페이지 테이블에 복제한다. 실패 시 error로 점프 */
    if (!pml4_for_each(parent->pml4, duplicate_pte, parent))
        goto error;
#endif
	/* 현재 스레드의 마지막으로 생성된 fd가 126이면 생성할 수 없기 때문에 error로 점프
    	(multi-oom의 테스트를 위한 생성제한 조건) */
	if (current->last_created_fd == 126) {
		goto error;
	}

	// e에 부모 프로세스의 fd_table의 시작 요소를 가져온다.
	struct list_elem* e = list_begin(&parent->fd_table);
    // parent_list에 부모 프로세스의 fd_table의 포인터를 가져온다.
	struct list *parent_list = &parent->fd_table;
    
    // 부모 프로세스의 fd_table에 데이터가 있으면
	if(!list_empty(parent_list)){
    	// fd_table을 끝까지 순회하며 
		for (e ; e != list_end(parent_list) ; e = list_next(e)){
        	// 현재 순회하고 있는 fd의 요소를 가져온다.
			struct file_descriptor* parent_fd =list_entry(e,struct file_descriptor, fd_elem);
			
            // 가져온 fd의 파일이 존재하면
            if(parent_fd->file != NULL){
            	// 새로 fd 구조체를 동적할당한다.
				struct file_descriptor *child_fd = malloc(sizeof(struct file_descriptor));
                // 자식의 fd 파일에 부모의 fd 파일 포인터를 담는다.
				child_fd->file = file_duplicate(parent_fd->file);
                // 자식의 fd를 부모의 fd와 동일하게 맞춘다.
				child_fd->fd = parent_fd->fd;
                // 자식의 fd_table에 새 fd요소를 추가한다.
				list_push_back(&current->fd_table, & child_fd->fd_elem);
			}
            // 각 과정 진행 후 자식 프로세스의 생성fd를 부모 프로세스의 fd로 설정
			current->last_created_fd = parent->last_created_fd;
		}
		current->last_created_fd = parent->last_created_fd;
	} else {
		current->last_created_fd = parent->last_created_fd;
	}

	if_.R.rax = 0; // 자식 프로세스의 리턴 값을 0으로 설정(자식 프로세스는 0 리턴이 정상) 

    // 로드가 완료될 때까지 기다리고 있던 부모 대기 해제
    sema_up(&current->process_sema);
    process_init();

    // 성공시 마지막으로 새로 생성된 프로세스로 전환한다.
    if (succ)
        do_iret(&if_);
// error로 점프되었을 시 세마포어를 증가시키고 TID_ERROR로 종료한다.
error:
    sema_up(&current->process_sema);
    exit(TID_ERROR);
}

 

< process_exec >

더보기
// 현재 실행중인 프로세스를 f_name으로 변경해 새로 실행한다.
int
process_exec (void *f_name) {

	char *file_name = f_name;
	bool success;
	
	/* 스레드 구조에서 intr_frame을 사용할 수 없습니다.
	 * 현재 스레드가 다시 예약되면 실행 정보를 회원에게 저장하기 때문입니다. */
	struct intr_frame _if;
	_if.ds = _if.es = _if.ss = SEL_UDSEG; // 데이터, 엑스트라, 스택 세그먼트들을 사용자 데이터 세그먼트로 설정
	_if.cs = SEL_UCSEG; // 코드 세그먼트를 사용자 코드 세그먼트로 설정
	_if.eflags = FLAG_IF | FLAG_MBS; // 인터럽트 플래그와 기본 상태 플래그를 설정
	
	// 현재 프로세스를 종료하고 자원 정리
	process_cleanup ();

	// 동시성 문제를 위해 lock을 걸어주고 file_name으로 불러와서 반환 값인 성공 여부를 success에 담는다.
	lock_acquire(&filesys_lock);
	success = load (file_name, &_if);
	lock_release(&filesys_lock);

	// 잘 받아오는지 테스트를 위한 hex_dump
	// hex_dump(_if.rsp, _if.rsp, USER_STACK - (uint64_t)_if.rsp, true);

	// 더 이상 필요하지 않은 file_name을 메모리 해제한다.
    palloc_free_page (file_name);
    
    // 불러오기 실패 시 -1 반환
	if (!success)
		return -1;

	// 불러온 프로세스를 실행하기 위해 인터럽트 리턴을 수행한다.
	do_iret (&_if);
    // 도달할 수 없고 반환되지 않는다.
	NOT_REACHED ();
}

 

< process_wait >

더보기
// 프로세스를 대기시킨다.
int
process_wait (tid_t child_tid) {
	/* 이 함수를 작성하기 전 다른 시스템 콜 테스트를 위해 for문으로 대기 시간을 야매로 설정해주었다. */
    // for(int i = 0; i < 3000000000; i++) {
    // }
    
    // 자식 스레드의 tid를 가져와서 t에 저장. 없으면 -1 반환
	struct thread *t = get_thread_from_tid(child_tid);
	if (t == NULL) {
		return -1;
	}

	// 세마포어를 감소시키고 자식프로세스가 종료될 때까지 부모 프로세스는 블락 상태로 유지
	sema_down(&t->wait_sema);
    // 자식 프로세스가 종료될 시, 부모 프로세스의 자식 목록에서 제거
	list_remove(&t->child_list_elem);

	// 세마포어를 증가시키며 블락 상태를 해제시킨다.
	sema_up(&t->exit_sema);

	// 자식 프로세스의 종료 상태를 반환
	return t->exit_status; 
}

 

< process_exit >

더보기
// 프로세스를 종료시킨다.
void
process_exit (void) {
	struct thread *t = thread_current();
    
    // pml4(가상 메모리 주소 공간을 가리키는 포인터)가 존재하면
	if (t->pml4 != NULL){
    	// 스레드의 이름과 exit의 상태를 출력
		printf("%s: exit(%d)\n", t->name, t->exit_status);
		// 현재 실행중인 프로세스(file)을 닫는다.
        file_close(t->running);
        // 닫고 나면 실행중인 프로세스를 NULL로 비우기
		t->running = NULL;
	}

	struct list *exit_list = &t->fd_table;
	struct list_elem *e = list_begin(&exit_list);
    
    // fd를 2부터 마지막 생성 fd까지 순회하면서 닫는다.
	for(int i = 2; i< t->last_created_fd; ++i){
		close(i);
	}

	process_cleanup(); // 프로세스를 종료하고 자원 정리
	sema_up(&t->wait_sema); // 자식 프로세스 종료를 부모 프로세스에 알리기 위해 sema를 증가
	sema_down(&t->exit_sema); // 완전히 종료되기전 다른 작업이 있으면 마무리하기 위해 블락하여 대기
}

 

< process_cleanup >

더보기
/* 현재 프로세스의 리소스를 확보합니다.*/
static void
process_cleanup (void) {
	struct thread *curr = thread_current ();

#ifdef VM
	supplemental_page_table_kill (&curr->spt);
#endif

	uint64_t *pml4;
	/* 현재 프로세스의 페이지 디렉터리를 삭제하고 커널 전용 페이지 디렉터리로 다시 전환합니다. */
	pml4 = curr->pml4;
	if (pml4 != NULL) {
		/* 여기서 올바른 순서는 매우 중요합니다. 
		 * 페이지 디렉토리를 전환하기 전에 cur->pagedir를 NULL로 설정해야 
		 * 타이머 인터럽트가 프로세스 페이지 디렉토리로 다시 전환할 수 없습니다.
		 * 프로세스의 페이지 디렉토리를 파기하기 전에 기본 페이지 디렉토리를 활성화해야 합니다. 
		 * 그렇지 않으면 활성화된 페이지 디렉토리가 해제(및 삭제)된 디렉토리가 됩니다 */
		curr->pml4 = NULL;
		pml4_activate (NULL);
		pml4_destroy (pml4);
	}
}

 

< process_activate >

더보기
 /* 네스트 스레드에서 사용자 코드를 실행할 CPU를 설정합니다.
 * 이 기능은 모든 컨텍스트 스위치에서 호출됩니다. */
void
process_activate (struct thread *next) {
	/* 스레드의 페이지 테이블을 활성화합니다.*/
	pml4_activate (next->pml4);

	/* 인터럽트 처리에 사용할 스레드의 커널 스택을 설정합니다. */
	tss_update (next);
}

 

< load >

더보기
/* FILE_NAME에서 ELF 실행 파일을 현재 스레드로 로드합니다.
 * 실행 파일의 진입 지점을 *RIP에 저장합니다
 * 초기 스택 포인터를 *RSP에 입력합니다.
 * 성공하면 true, 그렇지 않으면 false를 반환합니다. */
static bool
load (const char *file_name, struct intr_frame *if_) {
	struct thread *t = thread_current ();
	struct ELF ehdr; // ELF 파일의 헤더 정보를 저장하는 변수
	struct file *file = NULL;
	off_t file_ofs; // 파일 내에서의 위치를 저장할 변수 
	bool success = false;
	int i, j;

	//스택에 전달받은 인자를 쌓아주는 작업
	char *stk[64];
	int argc = 0;
	char *token, *save_ptr;

   	for (token = strtok_r (file_name, " ", &save_ptr); token != NULL; token = strtok_r (NULL, " ", &save_ptr)){
		stk[argc] = token;
		argc++;
	}

	/* 페이지 디렉토리를 할당하고 활성화 */
	t->pml4 = pml4_create ();
	if (t->pml4 == NULL)
		goto done;
	process_activate (thread_current ());

	// file_name에 맞는 실행 파일을 연다. 파일을 가져오지 못했으면 실패 메세지 출력 후 done으로 이동
	file = filesys_open (file_name);
	if (file == NULL) {
		printf ("load: %s: open failed\n", file_name);
		goto done;
	}
	// ELF 파일을 로드하는 과정의 일부이며, 실행 파일 헤더를 읽고 확인한다.
    // 조건들이 만족하지 않았을 경우 오류 메세지를 출력하고 done으로 이동
    /* ELF 파일은 세 가지로 분류되는데 헤더, 프로그램 헤더 테이블, 섹션 헤더 테이블로 구성된다.
    	UNIX나 그 계열 운영체제에서 사용되는 파일 형식 */
	if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr
			|| memcmp (ehdr.e_ident, "\177ELF\2\1\1", 7)
			|| ehdr.e_type != 2
			|| ehdr.e_machine != 0x3E // amd64
			|| ehdr.e_version != 1
			|| ehdr.e_phentsize != sizeof (struct Phdr)
			|| ehdr.e_phnum > 1024) {
		printf ("load: %s: error loading executable\n", file_name);
		goto done;
	}
    
	/* 프로그램 헤더 테이블을 순회하며 각 세그먼트 처리
    	(세그먼트는 실행 파일이 메모리에 로드될 때 필요한 정보를 담고 있다.) */
	file_ofs = ehdr.e_phoff; // 파일 내에서 프로그램 헤더 테이블의 시작 위치로 파일 위치 설정
    
    // 프로그램 헤더 테이블의 모든 세그먼트를 순회
	for (i = 0; i < ehdr.e_phnum; i++) {
		struct Phdr phdr; // 프로그램 헤더의 정보를 저장할 구조체
        
        // 파일 위치의 유효성을 검증해 음수거나, 파일 길이를 초과하면 done으로 이동(오류 처리)
		if (file_ofs < 0 || file_ofs > file_length (file))
			goto done;
            
		file_seek (file, file_ofs); // 현재 프로그램 헤더 위치로 포인터를 이동
        
        // 현재 프로그램 헤더 정보를 읽고 예상한 크기와 다르면 done으로 이동
		if (file_read (file, &phdr, sizeof phdr) != sizeof phdr)
			goto done;
            
		file_ofs += sizeof phdr; // 다음 프로그램 헤더로 위치 이동
        
        // 세그먼트의 타입에 따라 다른 처리를 위해 switch문 작성
		switch (phdr.p_type) {
            case PT_NULL:
            case PT_NOTE:
            case PT_PHDR:
            case PT_STACK:
            default:
                /* 위의 세그먼트들을 무시한다. */
                break;
            // 밑의 세 세그먼트는 done으로 이동(에러 처리)
            case PT_DYNAMIC:
            case PT_INTERP:
            case PT_SHLIB:
                goto done;
            // 세그먼먼트가 PT_LOAD일 때
            case PT_LOAD:
            	/* 세그먼트 유효성을 검증하고 load_segment함수를 통해 실제로 메모리에
                세그먼트를 불러온다. 세그먼트가 파일에서 차지하는 부분과 메모리에 차지해야 
                할 부분을 계산해, 필요한 부분은 디스크에서 읽고 나머지는 0으로 채운다. */
                if (validate_segment (&phdr, file)) {
                    bool writable = (phdr.p_flags & PF_W) != 0;
                    uint64_t file_page = phdr.p_offset & ~PGMASK;
                    uint64_t mem_page = phdr.p_vaddr & ~PGMASK;
                    uint64_t page_offset = phdr.p_vaddr & PGMASK;
                    uint32_t read_bytes, zero_bytes;
                    if (phdr.p_filesz > 0) {
                        /* 일반 세그먼트. 디스크에서 초기 부분을 읽고 나머지는 제로화한다. */
                        read_bytes = page_offset + phdr.p_filesz;
                        zero_bytes = (ROUND_UP (page_offset + phdr.p_memsz, PGSIZE)
                                - read_bytes);
                    } else {
                        /* 완전히 제로. 디스크에서 아무것도 읽지 마세요. */
                        read_bytes = 0;
                        zero_bytes = ROUND_UP (page_offset + phdr.p_memsz, PGSIZE);
                    }
                    if (!load_segment (file, file_page, (void *) mem_page,
                                read_bytes, zero_bytes, writable))
                        goto done;
                }
                else
                    goto done;
                break;
        }
	}

	t->running = file; // 현재 스레드의 실행중인 파일에 file 넣기 

	file_deny_write(file); // 실행 중인 파일에 대해 변경되는 것을 금지한다.(파일 변경 방지)
	
    /* 프로그램의 스택을 초기화 후, 인터럽트 프레임의 스택 포인터를 적절한 위치로 이동
    	이동에 실패 시 done으로 이동(에러 처리) */
	if (!setup_stack (if_))
		goto done;

	if_->rip = ehdr.e_entry; // 프로그램 실행을 시작할 메모리 주소를 지정한다.
    
    // stk에 저장된 인자들을 스택에 배치하고, 인터럽트 프레임의 스택 포인터를 조정한다.
	argument_stack(stk, argc, if_);
	if_->R.rsi = if_->rsp + 8; // 8바이트 더해 다음 인자를 가리키는 포인터로 설정
	if_->R.rdi = argc; // 프로그램에 전달된 인자의 수를 저장

	success = true; // 성공 처리를 위해 true로 저장

/* 위의 에러 처리로 done으로 보내졌을 시 success를 반환. 
	done으로 간 건 위의 true 저장을 안 거쳤기 때문에 false가 들어있음 */
done:
	// file_close (file);
	return success;
}

 

< validate_segment >

더보기
 /* PHDR에서 로드 가능한 유효한 세그먼트를 설명하는지 확인합니다
 * 파일을 입력하면 true, 그렇지 않으면 false를 반환합니다. */
static bool
validate_segment (const struct Phdr *phdr, struct file *file) {
	// p_offset과 p_vaddr의 페이지 오프셋이 같아야 합니다.
	if ((phdr->p_offset & PGMASK) != (phdr->p_vaddr & PGMASK))
		return false;

	// p_offset은 파일 내를 가리켜야 합니다.
	if (phdr->p_offset > (uint64_t) file_length (file))
		return false;

	// p_memsz는 최소한 p_filesz만큼 커야 합니다.
	if (phdr->p_memsz < phdr->p_filesz)
		return false;

	// 세그먼트는 비어 있지 않아야 합니다.
	if (phdr->p_memsz == 0)
		return false;

	// 가상 메모리 영역은 사용자 주소 공간 범위 내에서 시작과 끝이 모두 이루어져야 합니다.
	if (!is_user_vaddr ((void *) phdr->p_vaddr))
		return false;
	if (!is_user_vaddr ((void *) (phdr->p_vaddr + phdr->p_memsz)))
		return false;

	// 이 영역은 커널 가상 주소 공간 전체에 걸쳐 "wrap around"할 수 없습니다.
	if (phdr->p_vaddr + phdr->p_memsz < phdr->p_vaddr)
		return false;

	/* 매핑 페이지 0을 허용하지 않습니다. 
	 * 페이지 0을 매핑하는 것은 나쁜 생각일 뿐만 아니라, 
	 * 이를 허용하면 시스템 호출에 널 포인터를 전달한 사용자 코드가 
	 * memcpy() 등에서 널 포인터 인수를 통해 커널을 패닉시킬 가능성이 높습니다. */
	 
	if (phdr->p_vaddr < PGSIZE)
		return false;

	return true;
}

 

< get_thread_from_tid >

더보기
// tid(스레드 고유 id) 를 가져온다.
struct thread *get_thread_from_tid(tid_t thread_id){
	struct thread * t = thread_current();
	struct list* child_list = &t->child_list;
	struct list_elem* e;

	// 자식 프로세스를 처음부터 끝까지 순회하며 t에 각 요소 값을 가져와 같으면 tid를 반환
	for (e = list_begin (child_list); e != list_end (child_list); e = list_next (e))
	{
		t = list_entry(e, struct thread, child_list_elem);
		if (t->tid == thread_id){
			return t;
		}
	}
    // 다 돌아도 맞는게 없으면 NULL 반환
	return NULL; 
}

 

// VM 관련 함수도 작성되어 있는 부분이 있었는데 본인이 VM을 들어가지 못해서 보류했다.

728x90