linux printk 头文件,[转载]Linux Kernel中printk的内部实现

在头文件 中定义了 【8种可用的日志级别字符串】

KERN_EMERG 用于紧急事件消息,它们一般是系统崩溃之前提示的消息。

KERN_ALERT 用于需要立即采取动作的情况。

KERN_CRIT 临界状态,通常涉及严重的硬件或软件操作失败。

KERN_ERR 用于报告错误状态;设备驱动程序会经常使用KERN_ERR来报告来自硬件的问题。

KERN_WARNING 对可能出现问题的情况进行警告,这类情况通常不会对系统造成严重问题。

KERN_NOTICE 有必要进行提示的正常情形。许多与安全相关的状况用这个级别进行汇报。

KERN_INFO 提示性信息。很多驱动程序在启动的时候,以这个级别打印出它们找到的硬件信息。

KERN_DEBUG 用于调试信息。

dmesg是从kernel的ring buffer(环缓冲区)中读取信息的.

那什么是ring buffer呢?

在LINUX中,所有的系统信息(包内核信息)都会传送到ring

buffer中.而内核产生的信息由printk()打印出来。系统启动时所看到的信息都是由该函数打印到屏幕中。

printk()打出的信息往往以 <0>...<2>...

这的数字表明消息的重要级别。高于一定的优先级别会打印到屏幕上,否则只会保留在系统的缓冲区中(ring buffer)。

至于dmesg具体是如何从ring buffer中读取的,大家可以看dmesg.c源代码.很短,比较容易读懂.

是syslogd这个守护进程根据/etc/syslog.conf,将不同的服务产生的Log记录到不同的文件中.

LINUX系统启动后,由/etc/init.d/sysklogd先后启动klogd,syslogd两个守护进程。

其中klogd会通过syslog()系统调用或者读取proc文件系统来从系统缓冲区(ring

buffer)中得到由内核printk()发出的信息.而syslogd是通过klogd来读取系统内核信息.

1>

所有系统信息是输出到ring buffer中去的.dmesg所显示的内容也是从ring buffer中读取的.

2>

LINUX系统中/etc/init.d/sysklogd会启动2个守护进程:Klogd, Syslogd

3>

klogd是负责读取内核信息的,有2种方式:

syslog()系统调用(这个函数用法比较全,大家去MAN一下看看)直接的对/proc/kmsg进行读取(再这提一下,/proc/kmsg是专门输出内核信息的地方)

4>

Klogd的输出结果会传送给syslogd进行处理,syslogd会根据/etc/syslog.conf的配置把log信息输出到/var/log/下的不同文件中.

注意将printk与syslog接合使用,

用在内核开发方面很不错.

内核用的打印函数printk完全是和stdin或stdout无关的,因为一开始到start_kernel函数刚开始进入内核就可以用printk

函数了,而建立stdin和stdout是在init函数中实现的。有个问题,这里的代码中,建立stdin和stdout如下

if (open("/dev/null",

O_RDWR, 0) < 0)

printk("Warning:

unable to open an initial

console./n");

(void)

dup(0);

(void)

dup(0);

问题在于它打开的是/dev/null,而一般pc机上的linux打开的都是/dev/console,而且我把这几行代码删除也没有问题,所以我猜想这里建立stdin和stdout并没什么用,肯定在shell中建立了定位到串口的stdin和stdout。所以接下来还需要看看busybox的代码吧。

在这里还是主要分析一下printk实现的原理。

static spinlock_t logbuf_lock

= SPIN_LOCK_UNLOCKED; //定义logbuf_lock,并初始化为unlock状态

static char

log_buf[LOG_BUF_LEN];

//保存日志数据的缓冲区

#define LOG_BUF(idx) (log_buf[(idx) &

LOG_BUF_MASK])

static

DECLARE_MUTEX(console_sem); //定义全局互斥信号量console_sem并初始化为1

asmlinkage int printk(const char *fmt,

...)

{

va_list

args;

unsigned long

flags;

int

printed_len;

char

*p;

static char

printk_buf[1024];

static int

log_level_unknown = 1;

if

(oops_in_progress) // default :

oops_in_progress = 0

{

//oops_in_progress指示进程发生错误,只有在panic()函数中才等于1

//所以一般情况下下两句都不运行

spin_lock_init(&logbuf_lock); //初始化logbuf_lock

init_MUTEX(&console_sem); //初始化console_sem为互斥的信号量,初值为1

}

spin_lock_irqsave(&logbuf_lock,

flags);

//一般spin_lock在单cpu中无效的,所以spin_lock_irqsave真正的作用是关中断

和保存状态寄存器。

va_start(args,

fmt);

printed_len =

vsnprintf(printk_buf, sizeof(printk_buf), fmt,

args);

//先把数据格式化到printk_b

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux 内核驱动创建环形队列可以使用 `struct ring_buffer` 结构体,该结构体定义在 `include/linux/ring_buffer.h` 头文件。 下面是一个简单的创建环形队列的示例代码: ```c #include <linux/ring_buffer.h> #define RING_BUFFER_SIZE 4096 struct ring_buffer my_ring_buffer; // 在初始化函数创建环形队列 static int __init my_driver_init(void) { int ret; // 分配环形队列的内存空间 ret = ring_buffer_alloc(&my_ring_buffer, RING_BUFFER_SIZE, GFP_KERNEL); if (ret) { printk(KERN_ERR "Failed to allocate ring buffer\n"); return ret; } // 环形队列初始化 ring_buffer_reset(&my_ring_buffer); // ... 其他初始化操作 return 0; } // 在清理函数释放环形队列的内存空间 static void __exit my_driver_exit(void) { // 清空环形队列 ring_buffer_reset(&my_ring_buffer); // 释放环形队列的内存空间 ring_buffer_free(&my_ring_buffer); // ... 其他清理操作 } module_init(my_driver_init); module_exit(my_driver_exit); ``` 在上面的示例代码,我们首先定义了一个 `struct ring_buffer` 类型的全局变量 `my_ring_buffer`,并在初始化函数使用 `ring_buffer_alloc` 函数为其分配内存空间,然后使用 `ring_buffer_reset` 函数进行初始化操作。在清理函数,我们使用 `ring_buffer_reset` 函数清空环形队列并使用 `ring_buffer_free` 函数释放其内存空间。 需要注意的是,在使用环形队列时需要遵循一定的规则,如不能在断处理程序使用 `ring_buffer` 等。此外,在使用环形队列时还需要考虑到多线程访问的问题,需要进行同步保护。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值