프로젝트/Pint OS

[Pint OS] 에러: Kernel panic... thread_yield()

KimCookieYa 2023. 6. 5. 14:49

발생

 

Pint OS의 프로젝트 2, argument passing을 실행시켜보았다가 발생했다. formatting file system을 하다가 터진다.

 

Kernel panic in run: PANIC at ../../threads/thread.c:338 in thread_yield(): assertion `!intr_context ()' failed.

* backtrace

Call stack: 0x800421874b 0x80042072c0 0x800420a92f 0x8004214d12 0x8004209704 0x8004209b22 0x800420762b
Translation of call stack:
0x000000800421874b: debug_panic (lib/kernel/debug.c:32)
0x00000080042072c0: thread_yield (threads/thread.c:340)
0x000000800420a92f: sema_up (threads/synch.c:124)
0x0000008004214d12: interrupt_handler (devices/disk.c:526)
0x0000008004209704: intr_handler (threads/interrupt.c:353)
0x0000008004209b22: intr_entry (threads/intr-stubs.o:?)
0x000000800420762b: kernel_thread (threads/thread.c:456)

* devices/disk.c

static void
interrupt_handler (struct intr_frame *f) {
	struct channel *c;

	for (c = channels; c < channels + CHANNEL_CNT; c++)
		if (f->vec_no == c->irq) {
			if (c->expecting_interrupt) {
				inb (reg_status (c));               /* Acknowledge interrupt. */
				sema_up (&c->completion_wait);      /* Wake up waiter. */
			} else
				printf ("%s: unexpected interrupt\n", c->name);
			return;
		}

	NOT_REACHED ();
}

 

솔루션

 

stackoverflow

 

how to solve Pintos project2 userprogram intrcontext error?

Korea's KAIST Revised and Distributed Pintos KAIST Project The same error occurred in all tests in the project 2 user program, so I am asking you this question. As a result of backtrace, an error a...

stackoverflow.com

 

스택오버플로우에 솔루션이 존재했다.

 

 프로젝트 1에서 우선순위 스케줄링을 위해 sema_up() 함수에서 thread_yield()를 호출한 것이 문제가 되었다. formatting file system 이후 에러에 빠진 걸로 볼 때, 파일 시스템에서 sema_up을 호출할 때 externel interrupt를 끄지 않아서 assert가 발생한 문제인 걸로 추측된다.

 

* threads/thread.c

void
thread_yield (void) {
	struct thread *curr = thread_current ();
	enum intr_level old_level;

	ASSERT (!intr_context ()); // ASSERT!

	old_level = intr_disable ();
	if (curr != idle_thread)
		list_insert_ordered (&ready_list, &curr->elem, cmp_priority, NULL);
	do_schedule (THREAD_READY);
	intr_set_level (old_level);
}

 

 

sema_up() 함수 내의 test_max_priority() 함수 안에서 if 조건에 `!intr_context()`를 추가하면 해결된다. 이것으로 외부 인터럽트가 발생 중일 때는 thread_yield()를 실행하지 않도록 제한할 수 있다.

 

* threads/synch.c

/* Up or "V" operation on a semaphore.  Increments SEMA's value
   and wakes up one thread of those waiting for SEMA, if any.

   This function may be called from an interrupt handler. */
void
sema_up (struct semaphore *sema) {
	enum intr_level old_level;

	ASSERT (sema != NULL);

	old_level = intr_disable ();
	if (!list_empty (&sema->waiters)) {
		struct list_elem * max_elem = list_min(&sema->waiters, cmp_priority, NULL);
		list_remove(max_elem);
		thread_unblock (list_entry (max_elem, struct thread, elem));
	}

	sema->value++;
	test_max_priority(); // 여기로 들어간다.
	intr_set_level (old_level);
}

* threads/thread.c

/* compare the priorities of the currently running thread and the newly inserted one.
	Yield the CPU if the newly arriving thread has higher priority*/
void
test_max_priority (void) {
	if (list_empty(&ready_list))
		return;
	if (!intr_context() && cmp_priority(list_front(&ready_list), &thread_current()->elem, NULL)) {
		thread_yield();
	}
}