발생
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 ();
}
솔루션
스택오버플로우에 솔루션이 존재했다.
프로젝트 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();
}
}
'프로젝트 > Pint OS' 카테고리의 다른 글
[Pint OS] System Calls (2) (0) | 2023.06.11 |
---|---|
[Pint OS] 에러: missing "begin" message (0) | 2023.06.09 |
[Pint OS] System Calls (1) (0) | 2023.06.07 |
[Pint OS] User Memory Access (0) | 2023.06.07 |
[Pint OS] Argument Passing (0) | 2023.06.05 |