首页 > 编程知识 正文

printk打太多log,路程问题相向而行公式

时间:2023-05-03 15:03:26 阅读:165243 作者:1752

最近,当代码工程升级kernel版本后,发现代码中使用了for循环dump的几个值时,printk(「0x%x”,temp_data )被连续打印。

通过调查,我们发现从kernel4.9开始,printk连续打印需要强制添加KERN_CONT flag . 有关详细信息,请参见printk(andkern_cont[lwn.net] )。

添加KERN_CONT后,解决了以下问题,但发现了一些奇怪的现象。

example1:printk(txt1); //canbealsoprintk (kern _ cont ' txt1); printk(Kern_cont'txt2'; printk(Kern_cont'txt3'; 打印((n ); 输出为line 1: txt1txt2txt3line 2: line 3: example 2: printk (txt1); //canbealsoprintk (kern _ cont ' txt1); printk(Kern_cont'txt2'; printk(Kern_cont'txt3(n '; 打印((n ); 输出为line 1: txt1txt2txt3line 2: line 3: example : printk (txt1); //canbealsoprintk (kern _ cont ' txt1); printk(Kern_cont'txt2'; printk(Kern_cont'txt3(n '; printk(Kern_cont'n '; 输出为line 1: txt1txt2txt3line 2: example 43360 printk (txt1); printk(txt2); printk(Kern_cont'n '; 输出为line 1: txt1line 2: txt2line :

根据printk(andKERN_CONT[lwn.net]的printk的记述,KERN_CONT似乎只作用于以n结尾的字符串和KERN_CONT的使用

非对称边界框架(isinhowaformatstringwithoutanewlineistreated, whichiswhathaschanged.the kern _ cont ' logleeated a printk (thatlacksthatflagissupposedtostartanewlineinthelog—thoughthaththathed

当时在example1中,打印txt 1、txt 2、txt 3后使用printk(「n”)时,竟然发生了两次换行。 example 2也换了两次行。 这个看起来很正常。 在example3中只能换行一次,在example4中只能换行一次。 (打印txt2如果不对kernel 5.4的动作使用KERN_CONT,则原本会自动换行,之后再次换行printk 'n '的话似乎就不起作用了。 使用KERN_CONT后,对只有“n”的字符串的处理看起来有点特殊。

我在那里找到了源代码:

staticvoidcont_flush(void ) if ) cont.len==0) return; log_store(cont.caller_id,cont.facility,cont.level,cont.flags,cont.ts_nsec,NULL,0,cont.buf } staticboolcont _ add (u 32 caller _ id,int facility,int level,enum log_flags flags,const char *text,size_t len ) slititupinseparaterecords.*/if (cont.lenlensizeof ) cont.buf ) ) {cont_flush ); 返回假; (if (! cont.len (cont.facility=facility; cont.level=级别; cont.caller_id=caller_id; cont.ts_nsec=local_clock (; cont.flags=flags; }memcpy(cont.bufcont.len,text,len ); cont.len =len; //theoriginalflagscomefromthefirstline,//butlatercontinuationscanaddanewline.if (flags log _ u

NEWLINE) {cont.flags |= LOG_NEWLINE;cont_flush();}return true;}static size_t log_output(int facility, int level, enum log_flags lflags, const char *dict, size_t dictlen, char *text, size_t text_len){const u32 caller_id = printk_caller_id();/* * If an earlier line was buffered, and we're a continuation * write from the same context, try to add it to the buffer. */if (cont.len) {if (cont.caller_id == caller_id && (lflags & LOG_CONT)) {if (cont_add(caller_id, facility, level, lflags, text, text_len))return text_len;}/* Otherwise, make sure it's flushed */cont_flush();}/* Skip empty continuation lines that couldn't be added - they just flush */if (!text_len && (lflags & LOG_CONT))return 0;/* If it doesn't end in a newline, try to buffer the current line */if (!(lflags & LOG_NEWLINE)) {if (cont_add(caller_id, facility, level, lflags, text, text_len))return text_len;}/* Store it in the record log */return log_store(caller_id, facility, level, lflags, 0, dict, dictlen, text, text_len);}/* Must be called under logbuf_lock. */int vprintk_store(int facility, int level, const char *dict, size_t dictlen, const char *fmt, va_list args){static char textbuf[LOG_LINE_MAX];char *text = textbuf;size_t text_len;enum log_flags lflags = 0;/* * The printf needs to come first; we need the syslog * prefix which might be passed-in as a parameter. */text_len = vscnprintf(text, sizeof(textbuf), fmt, args);/* 甜甜的洋葱 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) {int kern_level;while ((kern_level = printk_get_level(text)) != 0) {switch (kern_level) {case '0' ... '7':if (level == LOGLEVEL_DEFAULT)level = kern_level - '0';break;case 'c':/* KERN_CONT */lflags |= LOG_CONT;}text_len -= 2;text += 2;}}if (level == LOGLEVEL_DEFAULT)level = default_message_loglevel;if (dict)lflags |= LOG_NEWLINE;return log_output(facility, level, lflags, dict, dictlen, text, text_len);}

上述只粘贴部分代码 调用流程为 vprintk_store --> log_output.重点逻辑在log_output函数,对应example 第一次printk不带换行会走到log_out中判断字符串没有换行调用cont_add先保存起来, 第二次printk 字符串使用KERN_CONT 走到log_out中判断cont.len不为0,且LOG_CONT flag置位, 继续cont_add. cont_add 缓存到txt3后,这时调用printk(“n”) 进入后cont.len仍然不为0,但是没有LOG_CONT flag,此时会cont_flush 将之前的flush输出(输出会换行)。cont_fush后函数并没有return,继续往下调用log_store再将“n”输出,故发生两次换行。

example2 中printk(KERN_CONT "txt3n"), 调用cont_add 缓存"txt3n" 在cont_add中检测到换行会cont_flush。此后printk("n")和example1结构一致。

example3中printk(KERN_CONT "txt3n"), 调用cont_add 缓存"txt3n" 在cont_add中检测到换行会cont_flush。此后调用printk(KERN_CONT "n")进入log_out,此时cont.len = 0,检测到text_len 等于0, 直接return,因此并没有发生实际的任何打印。

/* 甜甜的洋葱 and strip a trailing newline */
    if (text_len && text[text_len-1] == 'n') {
        text_len--;
        lflags |= LOG_NEWLINE;
    }

example4

printk txt1时会cont_add 缓存,打印txt2时 cont.len 不为0, 且没有LOG_CONT flag,会cont_flush 将前一次的缓存(txt1)flush输出(输出会换行),然后继续往下发现“txt2”仍然不带换行flag, 调用cont_add继续缓存,最后printk(KERN_CONT "n"), cont.len不为0且带LOG_CONT 调用cont_add加入缓存, cont_add函数中发现add的字符串以换行结尾,调用cont_flush输出。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。