strace: Fix issues with a few syscalls
[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
19 void print_lock(void)
20 {
21         if (output_lock_holder == core_id_early()) {
22                 output_lock_count++;
23                 return;
24         }
25         pcpui_var(core_id_early(), __lock_checking_enabled)--;
26         spin_lock_irqsave(&output_lock);
27         output_lock_holder = core_id_early();
28         output_lock_count = 1;
29 }
30
31 void print_unlock(void)
32 {
33         output_lock_count--;
34         if (output_lock_count)
35                 return;
36         output_lock_holder = -1;
37         spin_unlock_irqsave(&output_lock);
38         pcpui_var(core_id_early(), __lock_checking_enabled)++;
39 }
40
41 /* Regardless of where we are, unlock.  This is dangerous, and only used when
42  * you know you will never unwind your stack, such as for a panic. */
43 void print_unlock_force(void)
44 {
45         output_lock_holder = -1;
46         output_lock_count = 0;
47         spin_unlock_irqsave(&output_lock);
48         pcpui_var(core_id_early(), __lock_checking_enabled)++;
49 }
50
51 void putch(int ch, int **cnt)
52 {
53         cputchar(ch);
54         **cnt = **cnt + 1;
55 }
56
57 // buffered putch to (potentially) speed up printing.
58 // static buffer is safe because output_lock must be held.
59 // ch == -1 flushes the buffer.
60 void buffered_putch(int ch, int **cnt)
61 {
62         #define buffered_putch_bufsize 64
63         static char buf[buffered_putch_bufsize];
64         static int buflen = 0;
65
66         if(ch != -1)
67         {
68                 buf[buflen++] = ch;
69                 **cnt = **cnt + 1;
70         }
71
72         if(ch == -1 || buflen == buffered_putch_bufsize)
73         {
74                 cputbuf(buf,buflen);
75                 buflen = 0;
76         }
77 }
78
79 int vcprintf(const char *fmt, va_list ap)
80 {
81         int cnt = 0;
82         int *cntp = &cnt;
83         volatile int i;
84         va_list args;
85
86         print_lock();
87
88         va_copy(args, ap);
89         trace_vprintk(fmt, args);
90         va_end(args);
91
92         // do the buffered printf
93         vprintfmt((void*)buffered_putch, (void*)&cntp, fmt, ap);
94
95         // write out remaining chars in the buffer
96         buffered_putch(-1,&cntp);
97
98         print_unlock();
99
100         return cnt;
101 }
102
103 int cprintf(const char *fmt, ...)
104 {
105         va_list ap;
106         int cnt;
107
108         if (!fmt)
109                 return 0;
110
111         va_start(ap, fmt);
112         cnt = vcprintf(fmt, ap);
113         va_end(ap);
114
115         return cnt;
116 }