akaros/kern/src/printf.c
<<
>>
Prefs
   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. */
  15static spinlock_t output_lock = SPINLOCK_INITIALIZER_IRQSAVE;
  16static int output_lock_holder = -1;     /* core_id. */
  17static int output_lock_count;
  18bool panic_skip_print_lock;
  19
  20void 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
  35void 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. */
  50void 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
  58void 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.
  67void 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
  86int 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
 110int 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}
 124