Krafton Jungle/5. PintOS

[PintOS 3주차] Day 3

munsik22 2025. 5. 24. 22:45

wait 구현 중 다음과 같은 에러가 반복해서 나타났다.

Interrupt 0x0d (#GP General Protection Exception) at rip=8004220949
 cr2=0000000000000000 error=               0
rax cccccccccccccccc rbx 0000000000000000 rcx 00000080042221dd rdx 0000000000000005
rsp 0000008004241990 rbp 00000080042419a0 rsi 00000000000000bf rdi cccccccccccccccc
rip 0000008004220949 r8 000000800422220a  r9 00000080042183e2 r10 0000000000000000
r11 0000000000000216 r12 000000800421d5c6 r13 0000000000000000 r14 0000000000000000
r15 0000000000000000 rflags 00000006
es: 0010 ds: 0010 cs: 0008 ss: 0010
…

깃북 페이지의 Tips 세션을 보면 이런 내용이 적혀 있다.

The page allocator in threads/palloc.c and the block allocator in threads/malloc.c clear all the bytes in memory to '0xcc' at time of free. Thus, if you see an attempt to dereference a pointer like 0xcccccccc, or some other reference to 0xcc, there's a good chance you're trying to reuse a page that's already been freed.

rax, rdi 레지스터 값이 cccccccccccccccc 인 것으로 보아, 이미 free된 page를 접근하는 것으로 보인다. (참고)

pid_t fork (const char *thread_name, struct intr_frame *f);

기존의 fork()process_fork()에 인터럽트 프레임을 thread_current()->tf를 넘기는 방식을 사용했는데, fork의 인수로 stuct intr_frame *f를 추가해서 시스템 콜을 호출한 f 자체를 넘기도록 수정했더니 해당 문제는 해결되었다.


코드 중간 정리

🔸 구조체 정리

/* userprog/process.h */
struct fork_args {
    struct thread *parent;
    struct intr_frame *pf;
    struct child *child_info;
};
/* threads/thread.h */
struct thread {
    …
	int exit_status;
	struct thread *parent;			/* Parent of this thread */
	struct list children;			/* List of children this thread has */
	struct child *child_info;		/* Information of this thread as someone's child */
}
/* threads/thread.h */
struct child {
	tid_t tid;
	int exit_status;
	bool is_waited;
	bool is_exit;
	struct list_elem c_elem;
	struct semaphore c_sema;
};

🔹 fork 구현

pid_t fork (const char *thread_name, struct intr_frame *f) {
	if (!is_valid(thread_name)) exit(-1);
	return process_fork(thread_name, f);
}
tid_t process_fork (const char *name, struct intr_frame *if_) {
	/* Clone current thread to new thread.*/
	struct thread *curr = thread_current();
	struct fork_args *fa = palloc_get_page(PAL_ZERO);
	if (fa == NULL) return TID_ERROR;
	fa->parent = curr;
	fa->pf = if_;

	tid_t tid = thread_create (name, PRI_DEFAULT, __do_fork, fa);
	if (tid < 0) {
		palloc_free_page(fa);
		return TID_ERROR;
	}

	/* Parent process should never return from the fork until
	   it knows whether the child process successfully cloned. */
	struct child *child = get_child_by_tid(tid);
	if (child == NULL) {
		palloc_free_page(fa);
		return TID_ERROR;
	}
	fa->child_info = child;

	sema_down(&child->c_sema);  // Wait until child finishes __do_fork
	return tid;
}
static void __do_fork (void *aux) {
	/* TODO: somehow pass the parent_if. (i.e. process_fork()'s if_) */
	struct intr_frame if_;
	struct thread *current = thread_current ();
	struct fork_args *fa = (struct fork_args *) aux;
	struct thread *parent = fa->parent;

	current->parent = parent;
	current->child_info = fa->child_info;
	ASSERT(current->child_info != NULL);
	current->child_info->tid = current->tid;

	struct intr_frame *parent_if = fa->pf;
	bool succ = true;

	/* 1. Read the cpu context to local stack. */
	memcpy(&if_, parent_if, sizeof(struct intr_frame));
	if_.R.rax = 0; // Set child's rax to 0

	/* 2. Duplicate PT */
	current->pml4 = pml4_create();
	if (current->pml4 == NULL)
		goto error;

	process_activate (current);

	if (!pml4_for_each (parent->pml4, duplicate_pte, parent))
		goto error;

	/* TODO: Your code goes here.
	 * TODO: Hint) To duplicate the file object, use `file_duplicate`
	 * TODO:       in include/filesys/file.h. Note that parent should not return
	 * TODO:       from the fork() until this function successfully duplicates
	 * TODO:       the resources of parent.*/

	process_init ();

	/* TODO: Parent inherits file resources (e.g., opened file descriptor) to child */
	/* Copy file descripters from parent to newly created process */
	for (int i = 2; i < 64; i++) {
		if (parent->fdt[i] != NULL) current->fdt[i] = file_duplicate(parent->fdt[i]);
		else current->fdt[i] = NULL;
	}

	palloc_free_page(fa);
	sema_up(&current->child_info->c_sema);

	/* Finally, switch to the newly created process. */
	if (succ)
		do_iret (&if_);
error:
	thread_exit ();
}

🔹 wait 구현

int wait (pid_t pid) {
	return process_wait(pid);
}
int process_wait (tid_t child_tid UNUSED) {
	/* Find child process by using child_tid */
	if (child_tid == NULL) return -1;
	struct child *child = get_child_by_tid(child_tid);
	if (child == NULL) return -1;
	if (!child->is_waited) {
		child->is_waited = true;
		if (!child->is_exit) sema_down(&child->c_sema);
		int status = child->exit_status;
		list_remove(&child->c_elem);
		free(child);
		return status;
	}
	return -1;
}

🔸 process exit 구현

void process_exit (void) {
	struct thread *curr = thread_current ();

	/* Close all file and deallocate the FDT */
	for (int fd = 2; fd < 64; fd++) {
		if (curr->fdt[fd] != NULL) {
			file_close(curr->fdt[fd]);
			curr->fdt[fd] = NULL;
		}
	}

	if (curr->child_info != NULL) {
		curr->child_info->exit_status = curr->exit_status;
		curr->child_info->is_exit = true;
		sema_up(&curr->child_info->c_sema);
	}

	process_cleanup ();
}

🔸 init_child 구현

struct child *init_child(tid_t tid) {
	struct child *child = (struct child *)malloc(sizeof(struct child));
	if(child == NULL) return NULL;

	child->tid = tid;
	child->exit_status = 0;
	child->is_waited = false;
	child->is_exit = false;
	sema_init(&child->c_sema, 0);
	return child;
}
  • thread_create()t->child_info = init_child(tid); 추가

🔸 get_child_by_tid 구현

struct child *get_child_by_tid(tid_t tid) {
	struct thread *curr = thread_current();
	struct list_elem *e;

	for (e = list_begin(&curr->children); e != list_end(&curr->children); e = list_next(e)) {
		struct child *child = list_entry(e, struct child, c_elem);
		if (child->tid == tid)
			return child;
	}
	return NULL;
}

12 of 95 tests failed.

 

'Krafton Jungle > 5. PintOS' 카테고리의 다른 글

[PintOS 3주차] Day 5-6  (0) 2025.05.26
[PintOS 3주차] Day 4  (0) 2025.05.25
[PintOS 3주차] Day 1-2  (2) 2025.05.23
[PintOS 2주차] Day 8  (0) 2025.05.22
[PintOS 2주차] Day 7  (2) 2025.05.21