#include <stdio.h>
#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
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().
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()
/* 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);
+ 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. */
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++;
static void
release_console (void)
{
- if (!intr_context ())
+ if (!intr_context () && use_console_lock)
{
if (console_lock_depth > 0)
console_lock_depth--;
static bool
console_locked_by_current_thread (void)
{
- return intr_context () || lock_held_by_current_thread (&console_lock);
+ return (intr_context ()
+ || !use_console_lock
+ || lock_held_by_current_thread (&console_lock));
}
/* The standard vprintf() function,
{
acquire_console ();
while (*s != '\0')
- putchar_unlocked (*s++);
- putchar_unlocked ('\n');
+ putchar_have_lock (*s++);
+ putchar_have_lock ('\n');
release_console ();
return 0;
{
acquire_console ();
while (n-- > 0)
- putchar_unlocked (*buffer++);
+ putchar_have_lock (*buffer++);
release_console ();
}
putchar (int c)
{
acquire_console ();
- putchar_unlocked (c);
+ putchar_have_lock (c);
release_console ();
return c;
{
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++;