blob: 7b415d9d3bdf5bddfee6611a508ffc173e545774 [file] [log] [blame]
// 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;
}