【轉】Linux內核中printf的實現(printk與vprintk)

你們應該都在找printf的實現,其實linux內核中就有,我原本想查一下,既然linux覆蓋了中斷向量表,那麼怎麼輸出文字?就查printk的代碼,發現原來printk就是printf。代碼在printk.clinux


#printk
asmlinkage int printk( const char *fmt, ...)
{
         va_list args;
         int r;
 
         va_start (args, fmt);
         r = vprintk(fmt, args);
         va_end (args);
 
         return r;

}

# vsprintk
asmlinkage int vprintk( const char *fmt, va_list args)
{
         int printed_len = 0;
         int current_log_level = default_message_loglevel;
         unsigned long flags;
         int this_cpu;
         char *p;
 
         boot_delay_msec();
 
         preempt_disable();
         /* This stops the holder of console_sem just where we want him */
         raw_local_irq_save(flags);
         this_cpu = smp_processor_id();
 
         /*
          * Ouch, printk recursed into itself!
          */
         if (unlikely(printk_cpu == this_cpu)) {
                 /*
                  * If a crash is occurring during printk() on this CPU,
                  * then try to get the crash message out but make sure
                  * we can't deadlock. Otherwise just return to avoid the
                  * recursion and return - but flag the recursion so that
                  * it can be printed at the next appropriate moment:
                  */
                 if (!oops_in_progress) {
                         recursion_bug = 1;
                         goto out_restore_irqs;
                 }
                 zap_locks();
         }
 
         lockdep_off();
         spin_lock(&logbuf_lock);
         printk_cpu = this_cpu;
 
         if (recursion_bug) {
                 recursion_bug = 0;
                 strcpy (printk_buf, recursion_bug_msg);
                 printed_len = sizeof (recursion_bug_msg);
         }
         /* Emit the output into the temporary buffer */
         printed_len += vscnprintf(printk_buf + printed_len,
                                   sizeof (printk_buf) - printed_len, fmt, args);
 
 
#ifdef  CONFIG_DEBUG_LL
         printascii(printk_buf);
#endif
 
         /*
          * Copy the output into log_buf.  If the caller didn't provide
          * appropriate log level tags, we insert them here
          */
         for (p = printk_buf; *p; p++) {
                 if (new_text_line) {
                         /* If a token, set current_log_level and skip over */
                         if (p[0] == '<' && p[1] >= '0' && p[1] <= '7' &&
                             p[2] == '>' ) {
                                 current_log_level = p[1] - '0' ;
                                 p += 3;
                                 printed_len -= 3;
                         }
 
                         /* Always output the token */
                         emit_log_char( '<' );
                         emit_log_char(current_log_level + '0' );
                         emit_log_char( '>' );
                         printed_len += 3;
                         new_text_line = 0;
 
                         if (printk_time) {
                                 /* Follow the token with the time */
                                 char tbuf[50], *tp;
                                 unsigned tlen;
                                 unsigned long long t;
                                 unsigned long nanosec_rem;
 
                                 t = cpu_clock(printk_cpu);
                                 nanosec_rem = do_div(t, 1000000000);
                                 tlen = sprintf (tbuf, "[%5lu.%06lu] " ,
                                                 (unsigned long ) t,
                                                 nanosec_rem / 1000);
 
                                 for (tp = tbuf; tp < tbuf + tlen; tp++)
                                         emit_log_char(*tp);
                                 printed_len += tlen;
                         }
 
                         if (!*p)
                                 break ;
                 }
 
                 emit_log_char(*p);
                 if (*p == '\n' )
                         new_text_line = 1;
         }
 
         /*
          * Try to acquire and then immediately release the
          * console semaphore. The release will do all the
          * actual magic (print out buffers, wake up klogd,
          * etc).
          *
          * The acquire_console_semaphore_for_printk() function
          * will release 'logbuf_lock' regardless of whether it
          * actually gets the semaphore or not.
          */
         if (acquire_console_semaphore_for_printk(this_cpu))
                 release_console_sem();
 
         lockdep_on();
out_restore_irqs:
         raw_local_irq_restore(flags);
 
         preempt_enable();
         return printed_len;
}
相關文章
相關標籤/搜索