Overhaul lock_test.R
[akaros.git] / kern / src / printf.c
1 // Simple implementation of cprintf console output for the kernel,
2 // based on printfmt() and the kernel console's cputchar().
3
4 #include <arch/arch.h>
5 #include <ros/common.h>
6
7 #include <atomic.h>
8 #include <stdio.h>
9 #include <stdarg.h>
10 #include <smp.h>
11 #include <kprof.h>
12 #include <init.h>
13
14 /* Recursive lock.  Would like to avoid spreading these in the kernel. */
15 static spinlock_t output_lock = SPINLOCK_INITIALIZER_IRQSAVE;
16 static int output_lock_holder = -1;     /* core_id. */
17 static int output_lock_count;
18 bool panic_skip_print_lock;
19
20 void print_lock(void)
21 {
22         if (panic_skip_print_lock)
23                 return;
24
25         if (output_lock_holder == core_id_early()) {
26                 output_lock_count++;
27                 return;
28         }
29         pcpui_var(core_id_early(), __lock_checking_enabled)--;
30         spin_lock_irqsave(&output_lock);
31         output_lock_holder = core_id_early();
32         output_lock_count = 1;
33 }
34
35 void print_unlock(void)
36 {
37         if (panic_skip_print_lock)
38                 return;
39
40         output_lock_count--;
41         if (output_lock_count)
42                 return;
43         output_lock_holder = -1;
44         spin_unlock_irqsave(&output_lock);
45         pcpui_var(core_id_early(), __lock_checking_enabled)++;
46 }
47
48 /* Regardless of where we are, unlock.  This is dangerous, and only used when
49  * you know you will never unwind your stack, such as for a panic. */
50 void print_unlock_force(void)
51 {
52         output_lock_holder = -1;
53         output_lock_count = 0;
54         spin_unlock_irqsave(&output_lock);
55         pcpui_var(core_id_early(), __lock_checking_enabled)++;
56 }
57
58 void putch(int ch, int **cnt)
59 {
60         cputchar(ch);
61         **cnt = **cnt + 1;
62 }
63
64 // buffered putch to (potentially) speed up printing.
65 // static buffer is safe because output_lock must be held.
66 // ch == -1 flushes the buffer.
67 void buffered_putch(int ch, int **cnt)
68 {
69         #define buffered_putch_bufsize 64
70         static char buf[buffered_putch_bufsize];
71         static int buflen = 0;
72
73         if(ch != -1)
74         {
75                 buf[buflen++] = ch;
76                 **cnt = **cnt + 1;
77         }
78
79         if(ch == -1 || buflen == buffered_putch_bufsize)
80         {
81                 cputbuf(buf,buflen);
82                 buflen = 0;
83         }
84 }
85
86 int vcprintf(const char *fmt, va_list ap)
87 {
88         int cnt = 0;
89         int *cntp = &cnt;
90         volatile int i;
91         va_list args;
92
93         print_lock();
94
95         va_copy(args, ap);
96         trace_vprintk(fmt, args);
97         va_end(args);
98
99         // do the buffered printf
100         vprintfmt((void*)buffered_putch, (void*)&cntp, fmt, ap);
101
102         // write out remaining chars in the buffer
103         buffered_putch(-1,&cntp);
104
105         print_unlock();
106
107         return cnt;
108 }
109
110 int cprintf(const char *fmt, ...)
111 {
112         va_list ap;
113         int cnt;
114
115         if (!fmt)
116                 return 0;
117
118         va_start(ap, fmt);
119         cnt = vcprintf(fmt, ap);
120         va_end(ap);
121
122         return cnt;
123 }