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;
  18
  19void 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
  31void 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. */
  43void 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
  51void 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.
  60void 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
  79int 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
 103int 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}
 117