X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flib%2Fkernel%2Fconsole.c;h=0d031b5b4bdd6a2257f416bdf1fc1ffdbbb4398e;hb=53a7f5d0952a4595f252247f5ee3d017468eb57e;hp=d09801d984a6f2250b18f15d819dc781c521f741;hpb=838c30d0075a3ee0413ba4909944b37f4970a10d;p=pintos-anon diff --git a/src/lib/kernel/console.c b/src/lib/kernel/console.c index d09801d..0d031b5 100644 --- a/src/lib/kernel/console.c +++ b/src/lib/kernel/console.c @@ -3,11 +3,12 @@ #include #include "devices/serial.h" #include "devices/vga.h" +#include "threads/init.h" #include "threads/interrupt.h" #include "threads/synch.h" static void vprintf_helper (char, void *); -static void putchar_unlocked (uint8_t c); +static void putchar_have_lock (uint8_t c); /* The console lock. Both the vga and serial layers do their own locking, so it's @@ -16,6 +17,19 @@ static void putchar_unlocked (uint8_t c); from mixing their output, which looks confusing. */ static struct lock console_lock; +/* True in ordinary circumstances: we want to use the console + lock to avoid mixing output between threads, as explained + above. + + False in early boot before the point that locks are functional + or the console lock has been initialized, or after a kernel + panics. In the former case, taking the lock would cause an + assertion failure, which in turn would cause a panic, turning + it into the latter case. In the latter case, if it is a buggy + lock_acquire() implementation that caused the panic, we'll + likely just recurse. */ +static bool use_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(). @@ -31,7 +45,7 @@ static struct lock console_lock; intr_handler() - timer interrupt intr_set_level() serial_putc() - putchar_unlocked() + putchar_have_lock() putbuf() sys_write() - one process writing to the console syscall_handler() @@ -45,11 +59,21 @@ static int console_lock_depth; /* Number of characters written to console. */ static int64_t write_cnt; -/* Initializes the console. */ +/* Enable console locking. */ void console_init (void) { - lock_init (&console_lock, "console"); + lock_init (&console_lock); + use_console_lock = true; +} + +/* Notifies the console that a kernel panic is underway, + which warns it to avoid trying to take the console lock from + now on. */ +void +console_panic (void) +{ + use_console_lock = false; } /* Prints console statistics. */ @@ -63,7 +87,7 @@ console_print_stats (void) static void acquire_console (void) { - if (!intr_context ()) + if (!intr_context () && use_console_lock) { if (lock_held_by_current_thread (&console_lock)) console_lock_depth++; @@ -76,7 +100,7 @@ acquire_console (void) static void release_console (void) { - if (!intr_context ()) + if (!intr_context () && use_console_lock) { if (console_lock_depth > 0) console_lock_depth--; @@ -85,6 +109,16 @@ release_console (void) } } +/* Returns true if the current thread has the console lock, + false otherwise. */ +static bool +console_locked_by_current_thread (void) +{ + return (intr_context () + || !use_console_lock + || lock_held_by_current_thread (&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. */ @@ -107,8 +141,8 @@ puts (const char *s) { acquire_console (); while (*s != '\0') - putchar_unlocked (*s++); - putchar_unlocked ('\n'); + putchar_have_lock (*s++); + putchar_have_lock ('\n'); release_console (); return 0; @@ -120,7 +154,7 @@ putbuf (const char *buffer, size_t n) { acquire_console (); while (n-- > 0) - putchar_unlocked (*buffer++); + putchar_have_lock (*buffer++); release_console (); } @@ -129,7 +163,7 @@ int putchar (int c) { acquire_console (); - putchar_unlocked (c); + putchar_have_lock (c); release_console (); return c; @@ -141,15 +175,16 @@ vprintf_helper (char c, void *char_cnt_) { int *char_cnt = char_cnt_; (*char_cnt)++; - putchar_unlocked (c); + putchar_have_lock (c); } /* Writes C to the vga display and serial port. The caller has already acquired the console lock if appropriate. */ static void -putchar_unlocked (uint8_t c) +putchar_have_lock (uint8_t c) { + ASSERT (console_locked_by_current_thread ()); write_cnt++; serial_putc (c); vga_putc (c);