printk 是 Linux 内核中用于输出信息的函数,它可以将信息输出到各种不同的设备和位置,例如控制台、串口、日志文件等。
printk 函数的输出会被写入内核的环形缓冲区中,并由一个或多个后台进程将其传输到目标设备或位置。可以使用 dmesg 命令来查看内核环形缓冲区中的输出消息。此外,也可以将 printk 输出重定向到其他设备或位置,例如串口或日志文件。
需要注意的是,由于 printk 函数可能会在中断上下文或原子上下文中被调用,因此需要遵循一些特殊规则来确保其安全性和可用性。例如,在中断上下文中只能使用 printk 函数的非阻塞版本,而在原子上下文中则不能使用 printk 函数。此外,为了避免死锁等问题,还需要谨慎地使用 printk 函数以及与之相关的锁机制。
printk 是 Linux 内核中用于输出信息的函数。它的基本语法如下:
int printk(const char *fmt, ...);
其中,fmt 是格式化字符串,它指定了输出信息的格式,下面会介绍;… 表示可变参数列表,它可以传递多个参数给格式化字符串。
在Linux内核中,printk函数用于在内核中输出日志信息。printk函数支持不同的日志级别来区分日志的重要性和优先级。
这些日志级别的定义位于头文件
常用的日志级别包括:
可以通过在格式化字符串前加上相应的日志级别前缀来指定输出的日志级别。
举个栗子:
printk(KERN_WARNING "This is a warning message\n");
printk_test.c:
/*************************************************************************
> File Name: printk_test.c
> Author: WangDengtao
> Mail: [email protected]
> Created Time: 2023年04月02日 星期日 17时59分29秒
************************************************************************/
#include
#include
// 打印普通信息(info)
#define INFO(fmt, ...) \
printk(KERN_INFO "INFO: " fmt "\n", ##__VA_ARGS__)
static int __init my_module_init(void)
{
printk(KERN_INFO"Enter");
printk(KERN_DEBUG "Debugging information!\n");
printk(KERN_NOTICE "Common but important information!\n");
printk(KERN_WARNING "Warning message!\n");
printk(KERN_ERR "Error message!\n");
printk(KERN_CRIT "Critical states, you need to pay attention!\n");
printk(KERN_ALERT "Immediate action is needed!\n");
printk(KERN_EMERG "GIn an emergency, the system is unavailable!\n");
INFO("General Information!");
return 0;
}
static void __exit my_module_exit(void)
{
INFO("Exit");
}
module_init(my_module_init);
module_exit(my_module_exit);
/*添加LICENSE和作者信息,是来告诉内核,该模块带有一个自由许可证;没有这样的说明,在加载模块的时内核会“抱怨”.*/
MODULE_LICENSE("Dual BSD/GPL");//许可 GPL、GPL v2、Dual MPL/GPL、Proprietary(专有)等,没有内核会提示.
MODULE_AUTHOR("WangDengtao");//作者
MODULE_VERSION("V1.0");//版本
Makefile:
KERNAL_DIR ?= /lib/modules/$(shell uname -r)/build
PWD :=$(shell pwd)
obj-m := printk_test.o
all:
$(MAKE) -C $(KERNAL_DIR) M=$(PWD) modules
@make clear
clean:
@rm -f *.ko
clear:
@rm -f *.o *.cmd *.mod *.mod.c
@rm -rf *~ core .depend .tmp_versions Module.symvers modules.order -f
@rm -f .*ko.cmd .*.o.cmd .*.o.d
@rm -f *.unsigned
make之后就可以看见我们的.ko驱动文件了。
安装卸载驱动:
wangdengtao@wangdengtao-virtual-machine:~/wangdengtao/driver/x86$ sudo insmod printk_test.ko
wangdengtao@wangdengtao-virtual-machine:~/wangdengtao/driver/x86$ sudo rmmod printk_test
查看:
wangdengtao@wangdengtao-virtual-machine:~/wangdengtao/driver/x86$ sudo dmesg | tail -10
[ 4993.976274] Enter
[ 4993.976277] Debugging information!
[ 4993.976278] Common but important information!
[ 4993.976278] Warning message!
[ 4993.976279] Error message!
[ 4993.976281] Critical states, you need to pay attention!
[ 4993.976282] Immediate action is needed!
[ 4993.976282] GIn an emergency, the system is unavailable!
[ 4993.976283] INFO: General Information!
[ 4997.412881] INFO: Exit
包含的头文件:
#include
函数 atomic_set() 的功能是将原子类型的变量v的值设置为i。
static inline void atomic_set(atomic_t * v, int i)
原子类型 atomic_t :
typedef struct {
int counter;
} atomic_t;
counter 为一个int变量的计数器。
首先定义一个原子类型my_atomic,然后调用函数atomic_set()将其值设置为5,并通过函数atomic_read()将原子类型my_atomic的counter字段读出。由输出信息可知,调用atomic_set()后,原子类型的值由0变为了5。
atomic_set_test.c:
/*************************************************************************
> File Name: atomic_set_test.c
> Author: WangDengtao
> Mail: [email protected]
> Created Time: 2023年04月02日 星期日 19时12分55秒
************************************************************************/
#include
#include
#include
atomic_t my_atomic;
static int __init atomic_set_init(void)
{
int i = 5;
printk("before atomic_set, my_atomic.counter = %d\n", atomic_read(&my_atomic));
atomic_set(&my_atomic, i);
printk("after atomic_set, my_atomic.counter = %d\n", atomic_read(&my_atomic));
return 0;
}
static void __exit atomic_set_exit(void)
{
printk("exit!\n");
}
module_init(atomic_set_init);
module_exit(atomic_set_exit);
/*添加LICENSE和作者信息,是来告诉内核,该模块带有一个自由许可证;没有这样的说明,在加载模块的时内核会“抱怨”.*/
MODULE_LICENSE("Dual BSD/GPL");//许可 GPL、GPL v2、Dual MPL/GPL、Proprietary(专有)等,没有内核会提示.
MODULE_AUTHOR("WangDengtao");//作者
MODULE_VERSION("V1.0");//版本
Makefile:
KERNAL_DIR ?= /lib/modules/$(shell uname -r)/build
PWD :=$(shell pwd)
obj-m := atomic_set_test.o
all:
$(MAKE) -C $(KERNAL_DIR) M=$(PWD) modules
@make clear
clean:
@rm -f *.ko
clear:
@rm -f *.o *.cmd *.mod *.mod.c
@rm -rf *~ core .depend .tmp_versions Module.symvers modules.order -f
@rm -f .*ko.cmd .*.o.cmd .*.o.d
@rm -f *.unsigned
wangdengtao@wangdengtao-virtual-machine:~/wangdengtao/driver/x86$ sudo insmod atomic_set_test.ko
wangdengtao@wangdengtao-virtual-machine:~/wangdengtao/driver/x86$ sudo rmmod atomic_set_test
wangdengtao@wangdengtao-virtual-machine:~/wangdengtao/driver/x86$ sudo dmesg | tail -3
[ 9410.583005] before atomic_set, my_atomic.counter = 0
[ 9410.583029] after atomic_set, my_atomic.counter = 5
[ 9420.932523] exit!