X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flib%2Fkernel%2Fconsole.c;h=844b18468bde5c3b828bb4455213aed6949f0f13;hb=64e74e3536b95c4d0a46aec56bc373ad0f6d470b;hp=14c707a63681129a66463677d6e7916d80199855;hpb=b567bc2c70ab0e4146fc208bd30224d76ea1cf5f;p=pintos-anon diff --git a/src/lib/kernel/console.c b/src/lib/kernel/console.c index 14c707a..844b184 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(). @@ -23,17 +37,17 @@ static struct lock console_lock; lock_console() vprintf() - printf() - palloc() tries to grab the lock again + printf() - palloc() tries to grab the lock again palloc_free() - schedule_tail() - another thread dying as we switch threads + thread_schedule_tail() - another thread dying as we switch threads schedule() thread_yield() - intr_handler() - timer interrupt + intr_handler() - timer interrupt intr_set_level() serial_putc() - putchar_unlocked() + putchar_have_lock() putbuf() - sys_write() - one process writing to the console + sys_write() - one process writing to the console syscall_handler() intr_handler() @@ -42,18 +56,38 @@ static struct lock console_lock; counter. */ static int console_lock_depth; -/* Initializes the console. */ +/* Number of characters written to console. */ +static int64_t write_cnt; + +/* 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. */ +void +console_print_stats (void) +{ + printf ("Console: %lld characters output\n", write_cnt); } /* Acquires the console lock. */ 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++; @@ -66,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--; @@ -75,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. */ @@ -97,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; @@ -110,7 +154,7 @@ putbuf (const char *buffer, size_t n) { acquire_console (); while (n-- > 0) - putchar_unlocked (*buffer++); + putchar_have_lock (*buffer++); release_console (); } @@ -119,7 +163,7 @@ int putchar (int c) { acquire_console (); - putchar_unlocked (c); + putchar_have_lock (c); release_console (); return c; @@ -131,15 +175,17 @@ 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); }