| // Simple implementation of cprintf console output for the kernel, |
| // based on printfmt() and the kernel console's cputchar(). |
| |
| #include <arch/arch.h> |
| #include <ros/common.h> |
| |
| #include <atomic.h> |
| #include <stdio.h> |
| #include <stdarg.h> |
| #include <smp.h> |
| #include <kprof.h> |
| #include <init.h> |
| |
| /* Recursive lock. Would like to avoid spreading these in the kernel. */ |
| static spinlock_t output_lock = SPINLOCK_INITIALIZER_IRQSAVE; |
| static int output_lock_holder = -1; /* core_id. */ |
| static int output_lock_count; |
| |
| void print_lock(void) |
| { |
| if (output_lock_holder == core_id_early()) { |
| output_lock_count++; |
| return; |
| } |
| pcpui_var(core_id_early(), __lock_checking_enabled)--; |
| spin_lock_irqsave(&output_lock); |
| output_lock_holder = core_id_early(); |
| output_lock_count = 1; |
| } |
| |
| void print_unlock(void) |
| { |
| output_lock_count--; |
| if (output_lock_count) |
| return; |
| output_lock_holder = -1; |
| spin_unlock_irqsave(&output_lock); |
| pcpui_var(core_id_early(), __lock_checking_enabled)++; |
| } |
| |
| /* Regardless of where we are, unlock. This is dangerous, and only used when |
| * you know you will never unwind your stack, such as for a panic. */ |
| void print_unlock_force(void) |
| { |
| output_lock_holder = -1; |
| output_lock_count = 0; |
| spin_unlock_irqsave(&output_lock); |
| pcpui_var(core_id_early(), __lock_checking_enabled)++; |
| } |
| |
| void putch(int ch, int **cnt) |
| { |
| cputchar(ch); |
| **cnt = **cnt + 1; |
| } |
| |
| // buffered putch to (potentially) speed up printing. |
| // static buffer is safe because output_lock must be held. |
| // ch == -1 flushes the buffer. |
| void buffered_putch(int ch, int **cnt) |
| { |
| #define buffered_putch_bufsize 64 |
| static char buf[buffered_putch_bufsize]; |
| static int buflen = 0; |
| |
| if(ch != -1) |
| { |
| buf[buflen++] = ch; |
| **cnt = **cnt + 1; |
| } |
| |
| if(ch == -1 || buflen == buffered_putch_bufsize) |
| { |
| cputbuf(buf,buflen); |
| buflen = 0; |
| } |
| } |
| |
| int vcprintf(const char *fmt, va_list ap) |
| { |
| int cnt = 0; |
| int *cntp = &cnt; |
| volatile int i; |
| va_list args; |
| |
| print_lock(); |
| |
| va_copy(args, ap); |
| trace_vprintk(fmt, args); |
| va_end(args); |
| |
| // do the buffered printf |
| vprintfmt((void*)buffered_putch, (void*)&cntp, fmt, ap); |
| |
| // write out remaining chars in the buffer |
| buffered_putch(-1,&cntp); |
| |
| print_unlock(); |
| |
| return cnt; |
| } |
| |
| int cprintf(const char *fmt, ...) |
| { |
| va_list ap; |
| int cnt; |
| |
| if (!fmt) |
| return 0; |
| |
| va_start(ap, fmt); |
| cnt = vcprintf(fmt, ap); |
| va_end(ap); |
| |
| return cnt; |
| } |