printk学习使用

printk级别问题:

printk()
printk()应该是每一个驱动开发者最为亲密的伙伴了,我们常常将它与二分查找法结合在一起寻找代码中发生问题的位置。
通常情况下,对于代码中的两个printk()语句,如果一个正常执行,而另一个没有被执行,就说明问题发生在这两个printk()之间,接下来就可以在这个范围内应用二分查找法定位有问题的代码。
1. printk()与printf()
用户空间有printf(),内核空间有printk(),它们就如代表善与恶的命运双生子,即使长相功能如何的接近,都不能在代码中共存。
对于我们来说,最容易犯的错误是,在需要printk()的地方误用了printf(),而在需要printf()的地方却又误用了printk(),通常这都不会是因为不知道它们的区别,而只是习惯使然。民间流传有这样的说法:当你在编写用户空间应用程序的时候,下意识写出的都是printk(),那么就说明你是个标准的内核开发者了。
2. printk()的消息级别
printk()与printf()的一个重要区别就是前者可以指定消息的打印级别,内核根据这个指定的级别来决定是否将消息打印到终端上。如下表所示,printk()共有8个级别。
级别
 描述
 
KERN_EMERG
 紧急情况,系统可能会崩溃
 
KERN_ALERT
 必须立即响应
 
KERN_CRIT
 临界情况
 
KERN_ERR
 错误信息
 
KERN_WARNING
 警告信息
 
KERN_NOTICE
 普通的但可能需要注意的信息
 
KERN_INFO
 提示性信息
 
KERN_DEBUG
 调试信息
 
如果没有指定消息的级别,printk()会使用默认的DEFAULT_MESSAGE_LOGLEVEL(通常是KERN_WARNING)。
3. 控制台的日志级别(console_loglevel)
当printk指定的消息级别小于指定的控制台日志级别时,消息的内容就会显示在该控制台上。控制台的日志级别定义在include/linux/kernel.h文件中,默认为DEFAULT_CONSOLE_LOGLEVEL(值等于7),也就是说默认情况下,比KERN_DEBUG级别高的printk()消息内容都可以在控制台上显示。
我们可以执行下面的命令使任何级别的printk()消息都被打印在终端上
$ echo 8 > /proc/sys/kernel/printk
4. printk()的变体
内核在include/linux/kernel.h文件中提供了两个printk()的变体pr_debug和pr_info,它们的定义为:
235 #define pr_debug(fmt,arg...) \
236 printk(KERN_DEBUG fmt,##arg)
244 #define pr_info(fmt,arg...) \
245 printk(KERN_INFO fmt,##arg)
5. printk()不是万能的
printk()虽然很好用,但它并不是万能的,在系统启动时,终端还没有初始化之前,它并不能被使用,不过如果不是在调试系统的启动过程的话,这并不能算是个问题。
其实内核提供了一个printk()的变体early_printk(),专门用于在系统启动的初期在终端上打印消息,它与printk()的区别仅仅在于名字的不同以及它能够更早地工作。
 

函数printk的使用方法和printf相似,用于内核打印消息。printk根据日志级别(loglevel)对消息进行分类。

日志级别用宏定义,日志级别宏展开为一个字符串,在编译时由预处理器将它和消息文本拼接成一个字符串,因此printk 函数中日志级别宏和格式字符串间不能有逗号。

下面是两个printk的例子,一个用于打印调试信息,另一个用于打印临界条件信息。

printk(KERN_DEBUG "Here I am: %s:%i\n", _ _FILE_ _, _ _LINE_ _); 
printk(KERN_CRIT "I'm trashed; giving up on %p\n", ptr); 

printk的日志级别定义如下(在linux26/includelinux/kernel.h中):

#defineKERN_EMERG"<0>"/*紧急事件消息,系统崩溃之前提示,表示系统不可用*/
#defineKERN_ALERT"<1>"/*报告消息,表示必须立即采取措施*/
#defineKERN_CRIT"<2>"/*临界条件,通常涉及严重的硬件或软件操作失败*/
#defineKERN_ERR"<3>"/*错误条件,驱动程序常用KERN_ERR来报告硬件的错误*/
#defineKERN_WARNING"<4>"/*警告条件,对可能出现问题的情况进行警告*/
#defineKERN_NOTICE"<5>"/*正常但又重要的条件,用于提醒。常用于与安全相关的消息*/
#defineKERN_INFO"<6>"/*提示信息,如驱动程序启动时,打印硬件信息*/
#defineKERN_DEBUG"<7>"/*调试级别的消息*/

extern int console_printk[];

#define console_loglevel  (console_printk[0])
#define default_message_loglevel  (console_printk[1])
#define minimum_console_loglevel  (console_printk[2])
#define default_console_loglevel  (console_printk[3])

日志级别的范围是0~7,没有指定日志级别的printk语句默认采用的级别是 DEFAULT_ MESSAGE_LOGLEVEL,其定义列出如下(在linux26/kernel/printk.c中):

/*没有定义日志级别的printk使用下面的默认级别*/
#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING 警告条件*/

内核可把消息打印到当前控制台上,可以指定控制台为字符模式的终端或打印机等。默认情况下,“控制台”就是当前的虚拟终端。

为了更好地控制不同级别的信息显示在控制台上,内核设置了控制台的日志级别console_loglevel。printk日志级别的作用是打印一定级别的消息,与之类似,控制台只显示一定级别的消息。

当日志级别小于console_loglevel时,消息才能显示出来。控制台相应的日志级别定义如下:

/* 显示比这个级别更重发的消息*/
#define MINIMUM_CONSOLE_LOGLEVEL  1   /*可以使用的最小日志级别*/
#define DEFAULT_CONSOLE_LOGLEVEL  7 /*比KERN_DEBUG 更重要的消息都被打印*/

int console_printk[4] = {
DEFAULT_CONSOLE_LOGLEVEL,/*控制台日志级别,优先级高于该值的消息将在控制台显示*/
/*默认消息日志级别,printk没定义优先级时,打印这个优先级以上的消息*/
DEFAULT_MESSAGE_LOGLEVEL,
/*最小控制台日志级别,控制台日志级别可被设置的最小值(最高优先级)*/
MINIMUM_CONSOLE_LOGLEVEL,
DEFAULT_CONSOLE_LOGLEVEL,/* 默认的控制台日志级别*/
};

如果系统运行了klogd和syslogd,则无论console_loglevel为何值,内核消息都将追加到/var/log/messages中。如果klogd没有运行,消息不会传递到用户空间,只能查看/proc/kmsg。

变量console_loglevel的初始值是DEFAULT_CONSOLE_LOGLEVEL,可以通过sys_syslog系统调用进行修改。调用klogd时可以指定-c开关选项来修改这个变量。如果要修改它的当前值,必须先杀掉klogd,再加-c选项重新启动它。
通过读写/proc/sys/kernel/printk文件可读取和修改控制台的日志级别。查看这个文件的方法如下:

#cat /proc/sys/kernel/printk
6   4  1   7

上面显示的4个数据分别对应控制台日志级别、默认的消息日志级别、最低的控制台日志级别和默认的控制台日志级别。

可用下面的命令设置当前日志级别:

# echo 8 > /proc/sys/kernel/printk


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 北航os lab1中的printk是一个用于内核调试的函数。printk函数是Linux内核中一个非常重要的调试输出函数,用于在内核中输出调试信息。 printk函数的原型为: int printk(const char *fmt, ...); 该函数可以接受一个或多个参数,类似于C语言中的printf函数。第一个参数是一个格式化字符串,后面的参数根据格式化字符串中的占位符来确定输出的内容。 printk函数通过将信息打印到内核缓冲区中,然后再将缓冲区的内容发送到标准输出或日志文件中。这样可以避免在内核中直接使用标准输出函数,因为标准输出函数通常会产生内核安全问题。 在lab1中,我们通过使用printk函数来输出一些调试信息,以便我们在运行内核时能够观察到一些重要的状态信息。这些信息对于调试内核错误和理解内核运行过程非常有帮助。 在实际使用中,我们可以在代码中的关键位置调用printk函数输出调试信息,比如在函数调用的入口处、循环的每一次迭代中等。输出的信息可以是变量的值、函数的返回结果、状态标志等。通过观察这些输出信息,我们可以更好地理解内核的运行过程,并找出潜在的问题和改进的空间。 总之,北航os lab1中的printk函数是一个用于内核调试的重要函数,在调试内核错误和理解内核运行过程中发挥着非常重要的作用。 ### 回答2: 北航OS lab1中的printk是一个用于打印输出信息的函数。在操作系统编程中,打印输出信息对于调试和排错是非常重要的。printk函数可以将我们想要输出的信息打印到控制台或者文件中。该函数可以接受不同类型的参数,包括字符串、整数和指针等。 在lab1中,我们需要实现一个简化版的printk函数。通过实现这个函数,我们可以加深对操作系统内核的理解,学习和掌握操作系统中的内核级调试技术。 在实现printk函数时,需要考虑几个关键点。首先是参数的处理,我们需要根据参数的不同类型来确定打印输出的格式。其次是打印输出的位置,可以选择将打印的信息输出到控制台上,或者写入到一个文件中。最后是打印输出的性能优化,可以通过缓冲区和格式化输出等优化技术来提高打印输出的效率。 通过实现printk函数,我们可以在内核中方便地输出调试信息,帮助我们追踪和分析代码的执行流程,进而更好地理解操作系统的运行机制。同时,printk函数在操作系统开发中也是一个基础的工具函数,熟练掌握它对于后续的实验和项目开发都有很大的帮助。 总之,北航OS lab1中的printk是一个重要的函数,它可以帮助我们实现内核级调试和输出相关信息,对于操作系统的学习和开发都具有重要意义。 ### 回答3: 北航OS Lab1是指北京航空航天大学操作系统实验中的第一个实验,即实现一个简化版的printk函数。 printk函数是操作系统中用于将信息打印到屏幕或日志文件的函数,可以帮助调试程序或输出程序的运行状态。在北航OS Lab1的实验中,我们需要实现一个类似的函数。 具体实现的过程涉及以下步骤: 1. 实现字符串输出功能:我们需要编写代码来输出字符串,将字符串的各个字符逐一输出到屏幕或日志文件。 2. 实现格式化输出功能:在实际开发中,我们通常希望能够输出变量的值,而不仅仅是字符串。因此,我们需要实现格式化输出的功能,即能够根据不同的格式输出不同类型的变量。 3. 添加参数支持:为了使printk函数更加灵活,我们还需要实现可变参数的支持,即能够接收不确定数量的参数。 4. 添加调试信息:为了方便调试程序,我们还需要在输出的内容中添加相关的调试信息,比如输出所在的文件和行号。 在完成上述步骤后,我们就能够实现一个简化版的printk函数。它能够输出字符串、格式化输出不同类型的变量、接收可变数量的参数,并且在输出中添加调试信息。 总之,北航OS Lab1中的打印函数(printk)是一个基于字符串输出的简化版,通过实现字符串输出、格式化输出、参数支持和调试信息,我们能够实现一个功能相对完善的打印函数,用于帮助调试和输出程序运行状态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值