X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flib%2Fkernel%2Fconsole.c;h=14c707a63681129a66463677d6e7916d80199855;hb=a929199f73fce9d810c633dff21e2ed7b03bc16c;hp=803b46b393dca80c9773e165bdcf8715c2a67de5;hpb=9ab60037e59bb84c22d5648be7c0655fe1be820e;p=pintos-anon diff --git a/src/lib/kernel/console.c b/src/lib/kernel/console.c index 803b46b..14c707a 100644 --- a/src/lib/kernel/console.c +++ b/src/lib/kernel/console.c @@ -16,12 +16,65 @@ static void putchar_unlocked (uint8_t c); from mixing their output, which looks confusing. */ static struct lock console_lock; +/* It's possible, if you add enough debug output to Pintos, to + try to recursively grab console_lock from a single thread. As + a real example, I added a printf() call to palloc_free(). + Here's a real backtrace that resulted: + + lock_console() + vprintf() + printf() - palloc() tries to grab the lock again + palloc_free() + schedule_tail() - another thread dying as we switch threads + schedule() + thread_yield() + intr_handler() - timer interrupt + intr_set_level() + serial_putc() + putchar_unlocked() + putbuf() + sys_write() - one process writing to the console + syscall_handler() + intr_handler() + + This kind of thing is very difficult to debug, so we avoid the + problem by simulating a recursive lock with a depth + counter. */ +static int console_lock_depth; + +/* Initializes the console. */ void console_init (void) { lock_init (&console_lock, "console"); } +/* Acquires the console lock. */ +static void +acquire_console (void) +{ + if (!intr_context ()) + { + if (lock_held_by_current_thread (&console_lock)) + console_lock_depth++; + else + lock_acquire (&console_lock); + } +} + +/* Releases the console lock. */ +static void +release_console (void) +{ + if (!intr_context ()) + { + if (console_lock_depth > 0) + console_lock_depth--; + else + lock_release (&console_lock); + } +} + /* The standard vprintf() function, which is like printf() but uses a va_list. Writes its output to both vga display and serial port. */ @@ -30,13 +83,9 @@ vprintf (const char *format, va_list args) { int char_cnt = 0; - if (!intr_context ()) - lock_acquire (&console_lock); - + acquire_console (); __vprintf (format, args, vprintf_helper, &char_cnt); - - if (!intr_context ()) - lock_release (&console_lock); + release_console (); return char_cnt; } @@ -46,31 +95,33 @@ vprintf (const char *format, va_list args) int puts (const char *s) { - if (!intr_context ()) - lock_acquire (&console_lock); - + acquire_console (); while (*s != '\0') putchar_unlocked (*s++); putchar_unlocked ('\n'); - - if (!intr_context ()) - lock_release (&console_lock); + release_console (); return 0; } +/* Writes the N characters in BUFFER to the console. */ +void +putbuf (const char *buffer, size_t n) +{ + acquire_console (); + while (n-- > 0) + putchar_unlocked (*buffer++); + release_console (); +} + /* Writes C to the vga display and serial port. */ int putchar (int c) { - if (!intr_context ()) - lock_acquire (&console_lock); - + acquire_console (); putchar_unlocked (c); - - if (!intr_context ()) - lock_release (&console_lock); - + release_console (); + return c; }