Linux核心printk實現

來源:互聯網
上載者:User

標籤:printk linux

 基於MTK 6595分析,核心版本3.10.5

1 Printk函數分析

核心為Printk維護一個環形緩衝區,其大小為:

#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)

大小可以通過CONFIG_LOG_BUF_SHIFT去控制

1.1函數原型如下:

asmlinkage int printk(const char *fmt, ...)

{

         va_listargs;

         intr;

         va_start(args,fmt);

         r= vprintk_emit(0, -1, NULL, 0, fmt, args);

         va_end(args);

         returnr;

}

 

 

asmlinkage int vprintk_emit(int facility,int level,

                                const char *dict, size_t dictlen,

                                const char *fmt, va_list args)

{

         staticint recursion_bug;

         staticchar textbuf[LOG_LINE_MAX];

         char*text = textbuf;

         size_ttext_len;

         enumlog_flags lflags = 0;

         unsignedlong flags;

         intthis_cpu;

         intprinted_len = 0;

   int in_irq_disable, in_non_preempt;

   in_irq_disable = irqs_disabled();//是否為中斷上下文

   in_non_preempt = in_atomic();//是否為原子上下文

         vscnprintf(text,sizeof(textbuf), fmt, args);

         memset(text,0x0, sizeof(textbuf));

         boot_delay_msec(level);

        

/* This stops the holder of console_sem just where we want him */

         local_irq_save(flags);

//禁止本地中斷,因為printk可以在任何環境中使用,而下面又要擷取logbug_lock去保護環形緩衝區,所以需要禁止本地中斷,防止死結.

         this_cpu= smp_processor_id();

         /*

          * Ouch, printk recursed into itself!

          */

        

         lockdep_off();

         raw_spin_lock(&logbuf_lock);//禁止本地中斷

         logbuf_cpu= this_cpu ;

    //把log儲存到text中

         text_len= vscnprintf(text, sizeof(textbuf), fmt, args);

         /*mark and strip a trailing newline */

         if(text_len && text[text_len-1] == ‘\n‘) {

                   text_len--;

                   lflags|= LOG_NEWLINE;

         }

         /*strip kernel syslog prefix and extract log level or control flags */

         if(facility == 0) {

                   intkern_level = printk_get_level(text);//擷取資訊level

         if(level == -1)

                   level= default_message_loglevel;

    

#ifdef CONFIG_PRINTK_PROCESS_INFO

   if (in_irq_disable)

       __raw_get_cpu_var(printk_state) = ‘-‘;//如果為中斷上下文,在log中加”-“標誌

#ifdef CONFIG_MT_PRINTK_UART_CONSOLE

   else if (printk_disable_uart == 0)

       __raw_get_cpu_var(printk_state) = ‘.‘; //如果為非中斷上下文,在log中加”.”標誌

#endif

   else

       __raw_get_cpu_var(printk_state) = ‘ ‘;

#endif

        

         if(!(lflags & LOG_NEWLINE)) {

                   ………………………………………….

         }else {

                   boolstored = false;

                   if(!stored)

                            log_store(facility,level, lflags, 0,//把log儲存在環形緩衝區中,這個重點分析

                                       dict, dictlen, text, text_len);

         }

         printed_len+= text_len;

 

         /*

          * Try to acquire and then immediately releasethe console semaphore.

          * The release will print out buffers and wakeup /dev/kmsg and syslog()

          * users.

          *

          * The console_trylock_for_printk() functionwill release ‘logbuf_lock‘

          * regardless of whether it actually gets theconsole semaphore or not.

          */

         if(console_trylock_for_printk(this_cpu))//嘗試擷取控制台訊號量,

                   console_unlock();//輸出資訊到控制台

         lockdep_on();

out_restore_irqs:

         local_irq_restore(flags);//恢複本地cpu中斷

 

         returnprinted_len;

}

1.2 log_store 分析

 Log_store函數主要想環形緩衝區中儲存log資訊,環形緩衝區組織如下:

 (struct log +log_data) ---(struct log +log_data)—(struct log + log_data)……..

也就是說每行Log都是以struct log開頭,然後接著存放log 資料

structlog {

u64 ts_nsec;             /*timestamp in nanoseconds *//時間標誌

u16 len;             /*length of entire record *///總長度

u16 text_len;            /*length of text buffer */ //log 資料長度

u16 dict_len;             /*length of dictionary buffer */

u8 facility;                  /*syslog facility */

u8 flags:5;                  /*internal record flags */

u8 level:3;                  /*syslog level */ //調試級

};

另外核心還定義了四個全域變數來管理緩衝區

/* index and sequence number of the first record stored in thebuffer */

/*static*/ u64 log_first_seq; //指向當前可讀的struct log索引號

/*static*/ u32 log_first_idx; //指向環形緩衝區可以讀的位置

/* index and sequence number of the next record to store in thebuffer */

/*static*/ u64 log_next_seq;//指向當前可寫的struct log索引號

/*static*/ u32 log_next_idx; //指向環形緩衝區可寫的位置

 

static void log_store(int facility, int level,

                enum log_flags flags, u64 ts_nsec,

                const char *dict, u16 dict_len,

                const char *text, u16 text_len)

{

struct log *msg;

u32 size, pad_len;

    int this_cpu = smp_processor_id();

    char state =__raw_get_cpu_var(printk_state);

    /*printk prefix {*/

    char tbuf[50];

    unsigned tlen;

    if (console_suspended == 0) {

        //這裡給Log添加首碼:如

        // [  121.939790].(0)[124:bat_thread_kthr]

      121.939790: 目前時間

      .         : 處於非中斷上下文

(0)          : 在cpu 0上執行

124:bat_thread_kthr :在124號進程進程調用了printk,bat_thread_kthr為線程名

 

       tlen = snprintf(tbuf, sizeof(tbuf),"%c(%x)[%d:%s]",

               state, this_cpu,current->pid, current->comm);

    } else {

        tlen = snprintf(tbuf, sizeof(tbuf),"%c%x)", state, this_cpu);

    }

    /*printk prefix }*/

/* number of ‘\0‘ padding bytes to next message*/

size = sizeof(struct log) + text_len +tlen +dict_len;

pad_len = (-size) & (LOG_ALIGN - 1);

size += pad_len;

 

while (log_first_seq < log_next_seq) {

           u32 free;

           if (log_next_idx > log_first_idx)

                    free = max(log_buf_len -log_next_idx, log_first_idx);//選擇更大的free空間

           else

                    free = log_first_idx -log_next_idx; //log_next_idx和log_first_idx直接的記憶體空間

 

           if (free > size + sizeof(structlog)) //log_next_idx後的記憶體不足

                    break;

           /* drop old messages until we haveenough contiuous space */

           log_first_idx =log_next(log_first_idx);//把log_first_idx移到下一個,此時舊log會被覆蓋

           log_first_seq++;

}

 

//這種情況下需要重設log_next_idx

if (log_next_idx + size + sizeof(struct log)>= log_buf_len) {

           /*

            * This message + an additional empty headerdoes not fit

            * at the end of the buffer. Add an emptyheader with len == 0

            * to signify a wrap around.

            */

           memset(log_buf + log_next_idx, 0,sizeof(struct log));

           log_next_idx = 0;

}

 

/* fill message */ //填充資訊

msg = (struct log *)(log_buf + log_next_idx);

//memcpy(log_text(msg), text, text_len);

    memcpy(log_text(msg), tbuf, tlen);

memcpy(log_text(msg) + tlen, text, text_len);

    text_len += tlen;

msg->text_len = text_len;

memcpy(log_dict(msg), dict, dict_len);

msg->dict_len = dict_len;

msg->facility = facility;

msg->level = level & 7;

msg->flags = flags & 0x1f;

if (ts_nsec > 0)

           msg->ts_nsec = ts_nsec;

else

           msg->ts_nsec = local_clock();//擷取時間資訊

memset(log_dict(msg) + dict_len, 0, pad_len);

msg->len = sizeof(struct log) + text_len +dict_len + pad_len;

 

/* insert message */

log_next_idx += msg->len;//指向下一個可以寫位置

log_next_seq++;//sep相應加1

}

1.3 console_unlock分析

Console_unlock函數主要把環形緩衝區的buf輸出到串口,並喚醒需要讀取Log的線程

 

2 使用者空間擷取kernel  log

在printk中實現了/dev/kmsg和do_syslog系統調用,從而使用者空間可以通過syslog 或klogctl .

擷取核心log

Kmsg.c中通過調用do_syslog函數讀取log,從而實現/proc/kmsg函數

3. printk.c提供的其他函數

int __printk_ratelimit(const char *func) //每個5s之內,只能列印10個msg

bool kmsg_dump_get_line(struct kmsg_dumper*dumper, bool syslog,

                            char*line, size_t size, size_t *len)//buf中擷取一個record,也稱為一個行log

bool kmsg_dump_get_buffer(structkmsg_dumper *dumper, bool syslog,

                              char *buf, size_t size, size_t *len)//從buf中擷取size位元組的log

Linux核心printk實現

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.