CS318 - Pintos
Pintos source browser for JHU CS318 course
console.c
Go to the documentation of this file.
1 #include <console.h>
2 #include <stdarg.h>
3 #include <stdio.h>
4 #include "devices/serial.h"
5 #include "devices/vga.h"
6 #include "threads/init.h"
7 #include "threads/interrupt.h"
8 #include "threads/synch.h"
9 
10 static void vprintf_helper (char, void *);
11 static void putchar_have_lock (uint8_t c);
12 
13 /** The console lock.
14  Both the vga and serial layers do their own locking, so it's
15  safe to call them at any time.
16  But this lock is useful to prevent simultaneous printf() calls
17  from mixing their output, which looks confusing. */
18 static struct lock console_lock;
19 
20 /** True in ordinary circumstances: we want to use the console
21  lock to avoid mixing output between threads, as explained
22  above.
23 
24  False in early boot before the point that locks are functional
25  or the console lock has been initialized, or after a kernel
26  panics. In the former case, taking the lock would cause an
27  assertion failure, which in turn would cause a panic, turning
28  it into the latter case. In the latter case, if it is a buggy
29  lock_acquire() implementation that caused the panic, we'll
30  likely just recurse. */
31 static bool use_console_lock;
32 
33 /** It's possible, if you add enough debug output to Pintos, to
34  try to recursively grab console_lock from a single thread. As
35  a real example, I added a printf() call to palloc_free().
36  Here's a real backtrace that resulted:
37 
38  lock_console()
39  vprintf()
40  printf() - palloc() tries to grab the lock again
41  palloc_free()
42  thread_schedule_tail() - another thread dying as we switch threads
43  schedule()
44  thread_yield()
45  intr_handler() - timer interrupt
46  intr_set_level()
47  serial_putc()
48  putchar_have_lock()
49  putbuf()
50  sys_write() - one process writing to the console
51  syscall_handler()
52  intr_handler()
53 
54  This kind of thing is very difficult to debug, so we avoid the
55  problem by simulating a recursive lock with a depth
56  counter. */
57 static int console_lock_depth;
58 
59 /** Number of characters written to console. */
61 
62 /** Enable console locking. */
63 void
64 console_init (void)
65 {
67  use_console_lock = true;
68 }
69 
70 /** Notifies the console that a kernel panic is underway,
71  which warns it to avoid trying to take the console lock from
72  now on. */
73 void
75 {
76  use_console_lock = false;
77 }
78 
79 /** Prints console statistics. */
80 void
82 {
83  printf ("Console: %lld characters output\n", write_cnt);
84 }
85 
86 /** Acquires the console lock. */
87 static void
89 {
90  if (!intr_context () && use_console_lock)
91  {
94  else
96  }
97 }
98 
99 /** Releases the console lock. */
100 static void
102 {
103  if (!intr_context () && use_console_lock)
104  {
105  if (console_lock_depth > 0)
107  else
109  }
110 }
111 
112 /** Returns true if the current thread has the console lock,
113  false otherwise. */
114 static bool
116 {
117  return (intr_context ()
118  || !use_console_lock
120 }
121 
122 /** The standard vprintf() function,
123  which is like printf() but uses a va_list.
124  Writes its output to both vga display and serial port. */
125 int
126 vprintf (const char *format, va_list args)
127 {
128  int char_cnt = 0;
129 
130  acquire_console ();
131  __vprintf (format, args, vprintf_helper, &char_cnt);
132  release_console ();
133 
134  return char_cnt;
135 }
136 
137 /** Writes string S to the console, followed by a new-line
138  character. */
139 int
140 puts (const char *s)
141 {
142  acquire_console ();
143  while (*s != '\0')
144  putchar_have_lock (*s++);
145  putchar_have_lock ('\n');
146  release_console ();
147 
148  return 0;
149 }
150 
151 /** Writes the N characters in BUFFER to the console. */
152 void
153 putbuf (const char *buffer, size_t n)
154 {
155  acquire_console ();
156  while (n-- > 0)
158  release_console ();
159 }
160 
161 /** Writes C to the vga display and serial port. */
162 int
163 putchar (int c)
164 {
165  acquire_console ();
166  putchar_have_lock (c);
167  release_console ();
168 
169  return c;
170 }
171 
172 /** Helper function for vprintf(). */
173 static void
174 vprintf_helper (char c, void *char_cnt_)
175 {
176  int *char_cnt = char_cnt_;
177  (*char_cnt)++;
178  putchar_have_lock (c);
179 }
180 
181 /** Writes C to the vga display and serial port.
182  The caller has already acquired the console lock if
183  appropriate. */
184 static void
186 {
188  write_cnt++;
189  serial_putc (c);
190  vga_putc (c);
191 }
putchar
int putchar(int c)
Writes C to the vga display and serial port.
Definition: console.c:163
uint8_t
unsigned char uint8_t
Definition: stdint.h:20
console_lock_depth
static int console_lock_depth
It's possible, if you add enough debug output to Pintos, to try to recursively grab console_lock from...
Definition: console.c:57
lock_release
void lock_release(struct lock *lock)
Releases LOCK, which must be owned by the current thread.
Definition: synch.c:229
intr_context
bool intr_context(void)
Returns true during processing of an external interrupt and false at all other times.
Definition: interrupt.c:212
lock_init
void lock_init(struct lock *lock)
Initializes LOCK.
Definition: synch.c:176
use_console_lock
static bool use_console_lock
True in ordinary circumstances: we want to use the console lock to avoid mixing output between thread...
Definition: console.c:31
console_panic
void console_panic(void)
Notifies the console that a kernel panic is underway, which warns it to avoid trying to take the cons...
Definition: console.c:74
vga.h
putchar_have_lock
static void putchar_have_lock(uint8_t c)
Writes C to the vga display and serial port.
Definition: console.c:185
console.h
console_lock
static struct lock console_lock
The console lock.
Definition: console.c:18
console_locked_by_current_thread
static bool console_locked_by_current_thread(void)
Returns true if the current thread has the console lock, false otherwise.
Definition: console.c:115
int64_t
signed long long int int64_t
Definition: stdint.h:16
lock_held_by_current_thread
bool lock_held_by_current_thread(const struct lock *lock)
Returns true if the current thread holds LOCK, false otherwise.
Definition: synch.c:242
interrupt.h
buffer
static struct intq buffer
Stores keys from the keyboard and serial port.
Definition: input.c:7
release_console
static void release_console(void)
Releases the console lock.
Definition: console.c:101
stdarg.h
init.h
printf
int printf(const char *format,...)
Writes formatted output to the console.
Definition: stdio.c:79
__vprintf
void __vprintf(const char *format, va_list args, void(*output)(char, void *), void *aux)
Internal functions.
Definition: stdio.c:157
vprintf_helper
static void vprintf_helper(char, void *)
Helper function for vprintf().
Definition: console.c:174
vprintf
int vprintf(const char *format, va_list args)
The standard vprintf() function, which is like printf() but uses a va_list.
Definition: console.c:126
console_print_stats
void console_print_stats(void)
Prints console statistics.
Definition: console.c:81
write_cnt
static int64_t write_cnt
Number of characters written to console.
Definition: console.c:60
stdio.h
va_list
__builtin_va_list va_list
GCC has <stdarg.h> functionality as built-ins, so all we need is to use it.
Definition: stdarg.h:7
puts
int puts(const char *s)
Writes string S to the console, followed by a new-line character.
Definition: console.c:140
ASSERT
#define ASSERT(CONDITION)
This is outside the header guard so that debug.h may be included multiple times with different settin...
Definition: debug.h:31
serial.h
vga_putc
void vga_putc(int c)
Writes C to the VGA text display, interpreting control characters in the conventional ways.
Definition: vga.c:52
acquire_console
static void acquire_console(void)
Acquires the console lock.
Definition: console.c:88
console_init
void console_init(void)
Enable console locking.
Definition: console.c:64
s
static uint8_t s[256]
RC4-based pseudo-random number generator (PRNG).
Definition: random.c:17
putbuf
void putbuf(const char *buffer, size_t n)
Writes the N characters in BUFFER to the console.
Definition: console.c:153
serial_putc
void serial_putc(uint8_t byte)
Sends BYTE to the serial port.
Definition: serial.c:99
lock_acquire
void lock_acquire(struct lock *lock)
Acquires LOCK, sleeping until it becomes available if necessary.
Definition: synch.c:193
synch.h
lock
Lock.
Definition: synch.h:21